/* ============================================================================
   The mockup kit. Every product view on this site is static DOM built here.
   ----------------------------------------------------------------------------
   Six rules the whole kit obeys:

   1. 1:1 scale, always. There is no transform: scale() anywhere in a mockup's
      ancestor chain. A 1232px shell is 1232px at every viewport and gets
      CROPPED by its container, never shrunk. Shrinking a UI is what makes a
      marketing screenshot read as a picture of software instead of software.

   2. Every mockup sits inside a frame, and the frame decides what survives.
      .mk-plate is the shaded stage, and it keeps all four of its edges;
      .mk-crop is the window inside it, framing one rectangle of a bigger
      artifact at a chosen area of focus. Nothing floats loose on the page.

   3. Colour is state only. Green passed, amber waiting, red failed, and the
      shape carries the state too, so the colour is redundant.

   4. NOTHING IS HARD-CODED DARK. The product has no fixed-dark surface: its
      panels read --bg and --ink at runtime, so a light theme gets a light
      panel, and its template banner is written in --ink/--s1 so it inverts.
      A pinned hex is the one defect that cannot be fixed by a theme toggle,
      and a black slab in the middle of a light page is what a mockup built
      against an older product looks like. Every value in this file resolves
      through ./ds/tokens.css.

   5. ONE BACKDROP. Every mockup block on the site, the hero one included,
      is a .mk-plate and therefore carries the same soft vertical shade, the
      same 12px dot field, the same radius, the same single hairline AND THE
      SAME SHAPE. Every window on the site is 16:10 and its height follows its
      column, so a full-measure block and a chapter block are different sizes
      and the same shape, which is what reads as one system.
      The recipe lives in the --plate-* custom properties below, once, so a
      section cannot quietly invent its own stage.

   6. ONE CONTROL LADDER, and it is the ladder in the block below. A new size
      is not a design decision, it is a bug.
   ============================================================================ */

/* --------------------------------------------------------------------------
   THE LADDERS. Read these before adding any control anywhere in the kit or in
   site.css, and do not add a step.

   HEIGHT   40px  --control-h       a primary action: a site CTA, a copyable
                                    command row, a client tab
            36px  --control-h-sm    the header CTA and the header icon buttons,
                                    so the whole nav bar fits in 60px
            32px  --control-h-xs    THE DEFAULT. Every tab, segment, chip,
                                    suggestion, icon button and product row
            28px  --control-h-2xs   dense only: a copy button over a code block,
                                    a control inside a floating board bar
            20px  (--mk-tag)        a LABEL, never a control: .mk-pill and the
                                    two canvas annotations

   RADIUS    6px  --r-sm            the 20px label only
             8px  --mk-r            EVERY control from 28px to 40px, and every
                                    card nested inside a framed window
            16px  --r-xl            every framed window: the shell, the crop,
                                    a code card, a table, the chat panel
            20px  --plate-r         the stage, and nothing else
            50%                     the ONLY sanctioned circles: a status dot,
                                    the ringed status disc and its badge, an
                                    account avatar. border-radius: 9999px is
                                    banned everywhere else in this file.

   A tab and a secondary button are therefore the same object at 32px and 8px,
   which is the point: Activity / Plan / Results and Canvas / Steps / Code are
   one control, declared once in the .mk-tab block.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   THE STAGE RECIPE. One shade, one dot field, one height, two themes, and
   every number below was measured off the running page rather than guessed.

   TWO ENDS, NOT TWO TOKENS. The shade always runs light at the top to dark at
   the bottom, and the tokens that sit at those ends swap between themes: --s1
   is pure white in light and the darkest chrome in dark. Naming the ends
   (--plate-hi / --plate-lo) is what keeps the direction fixed with one
   gradient declaration.

   WHY THE OLD GRADIENT WAS WRONG, and it was wrong three ways:

     1. It ran at 176deg. Four degrees off vertical displaces the ramp
        sideways by tan(4deg) x 1352 = 94px across a wide stage, so the same y
        is up to 94px further down the ramp on one side and the block reads as
        a skewed vignette with its bright corner at top-RIGHT. It is 180deg.
     2. Its middle stop WAS --s2, and --s2 was also the background-color, so
        the vertical centre of the stage, which is exactly where the artifact
        sits, was flat #eef1f4. A white product card on #eef1f4 is ~ΔL 11, so
        the frame whose whole job is to say "this is a thing being shown to
        you" nearly vanished at the one place it mattered. The middle stop is
        now 55% of the way from hi to lo (light ~#f6f7f9), which restores a
        monotone ramp and puts the artifact's edge back at ~ΔL 20.
     3. Nothing was measured. Now it is: see the DOT block below.
   -------------------------------------------------------------------------- */
:root, [data-theme="light"] {
  --plate-hi: var(--s1);
  --plate-lo: var(--s2);
  --plate-lip: color-mix(in srgb, var(--s1) 90%, transparent);
}
[data-theme="dark"] {
  --plate-hi: var(--s2);
  --plate-lo: var(--bg);
  --plate-lip: color-mix(in srgb, var(--s3) 92%, transparent);
}
/* Declared after both theme blocks and touching neither of the two properties
   they set, so there is nothing to cascade against: the var()s resolve on the
   root element against whichever theme block won. ONE definition, both themes.
   --------------------------------------------------------------------------
   THE DOT FIELD, and it is the product's own, not a quieter cousin of it.

   The site's field was invisible, and it was invisible for three compounding
   reasons, all measured on the rendered hero stage at 1352 x 721:

     1. A mask killed it. `mask: linear-gradient(black 0%, transparent 72%)`
        makes effective alpha 0.08 x (1 - y / (0.72 x H)), which is
        mathematically ZERO below y = 519 on a 721px stage. Measured ΔL down
        the gutter: 40.1 at y=0, 16.9 at y=96, 11.7 at y=288, 5.0 at y=480,
        2.0 at y=576 and below. The artifact occupied y 40 to 680. The reader
        only ever saw dots in the 40px sliver above it.
     2. The alpha was a third of the product's (8% against 22%) at double the
        pitch (24px against 12px), which is about 11x less ink per unit area
        than the app's own canvas.
     3. The field it sat on was the wrong shade, so an 8% dot on a near-grey
        --s2 was a ~2-luminance step before the mask even applied.

   Two of those three were bugs and the third was an over-correction. The mask
   is gone and it stays gone. The pitch is the product's 12px and stays there.

   The ALPHA is not the product's, and that was the over-correction. The fix
   went to --flow-grid-dot, 22% ink, on the reasoning that the app's own canvas
   is the honest value. It is the honest value FOR THE APP: there the lattice is
   a work surface a node gets dragged onto and snapped to, so it has to be read
   as a grid. Here it is the field a product crop sits on, and at 22% over a
   12px pitch it is the loudest thing in the section, measured at ΔL 51.9, louder than the artifact it exists to hold.

   So this value belongs to the page: 4.5% ink, a fifth of the app's, which lands
   the field at ΔL ~11 in both themes. Present, even, unmistakably a lattice, and
   quieter than every line in the crop above it. Copying a token across a context
   boundary is not the same as being consistent with it.
   -------------------------------------------------------------------------- */
:root {
  --plate-mid: color-mix(in srgb, var(--plate-lo) 55%, var(--plate-hi));
  --plate-dot: color-mix(in srgb, var(--ink) 4.5%, transparent);
  --plate-grid: 12px;
  --plate-r: var(--r-xl);
  --plate-pad: clamp(var(--sp6), 6vw, calc(var(--sp8) + var(--sp4)));

  /* --------------------------------------------------------------------------
     ONE ASPECT RATIO, 16:10, AND NOT ONE HEIGHT.

     This ran on a fixed 560px height for one release and that was the bug the
     owner kept pointing at. Fixing the HEIGHT while the site has two block
     widths does not make the blocks consistent, it makes them different SHAPES:
     the full-measure block came out 1232 x 560, a 2.20:1 letterbox, and the
     off-centred chapter block came out 676 x 560, a 1.21:1 portrait. Neither is
     a screen. No monitor, laptop or phone has ever been 2.2:1, so an app shown
     at that ratio does not read as software however faithfully it is rebuilt.

     Measured off the reference, cursor.com at a 1512 viewport: the hero window
     is 1080 x 620 (1.74:1) and the second one 920 x 600 (1.53:1). Two different
     SIZES, one family of shapes, which is the opposite of what a fixed height
     produces. 16:10 sits in the middle of that range and is the canonical
     screen ratio, so every window on this site is 16:10 and the height follows
     the column: 1232 x 770 at full measure, 676 x 422 in a chapter.

     THE COROLLARY, and it is also the fix for "empty columns": a region whose
     natural height is 210 IS NOT A CROP. Mounting a 210-tall component on a
     700-tall stage is what produced the empty blocks. Those go beside copy or
     into a card grid. Only a region that fills its window gets a stage.
     -------------------------------------------------------------------------- */
  --plate-ar: 16 / 10;
  /* The standalone chat panel is not a window onto a bigger app, so it has no
     ratio to inherit and keeps an explicit height. */
  --panel-h: 560px;
}

.mk {
  /* Geist inside a mockup. Marketing type and product type must be one system
     or every crop reads as a foreign object pasted onto the page. */
  font-family: var(--font);

  /* THE PRODUCT'S OWN BASELINE, and it is deliberately NOT the site's.
     site.css runs a 1rem (16px) base because a launch page is read by someone
     who does not know the words yet. The product runs 14px, because a
     dashboard is scanned by someone who does. Every size in this file is
     therefore an absolute px value taken off the running app, and this
     declaration pins the inherited size too, so a mockup cannot pick up the
     site's step through an element nobody remembered to size.

     A crop that renders the product's UI text bigger than the product does has
     stopped being a crop: it is a redraw at the wrong scale, and the reader
     registers it immediately as a picture of software rather than software.
     Raise the site scale as far as it needs to go. Never raise this one. */
  font-size: 14px;

  /* Two radii, and they are not interchangeable. --mk-radius is the FRAMED
     WINDOW: the shell, the crop, the code card, a table, the chat panel, and
     it is the same 16px the site's own cards use, so a mockup and the card
     beside it are the same object. --mk-r is the PRODUCT radius, and inside a
     Studio crop it is the only one allowed, because the Studio has exactly one
     radius. A 14px corner inside the shell is the fastest way to make a
     rebuild read as a redraw. */
  --mk-radius: var(--r-xl);
  --mk-r: 8px;
  --mk-bar: 40px;              /* a marketing window's title strip     */
  --mk-head: var(--header-h);  /* a product pane header, 56px          */
  --mk-ctl-lg: var(--control-h);      /* 40 */
  --mk-ctl: var(--control-h-xs);      /* 32, THE product control height */
  --mk-ctl-sm: var(--control-h-2xs);  /* 28 */
  --mk-tag: 20px;              /* a label, and never a control         */
  --mk-pad: 12px;

  /* ONE ELEVATION RECIPE, AND IT IS A RING. Measured off both apps: every
     .app-card and .app-table in the dashboard computes box-shadow: none, and
     separates from the page by fill plus a 1px hairline, nothing else. A
     rebuilt product window carrying three shadow layers reads heavier than the
     application it quotes, which is the tell that it was drawn rather than
     measured. The STAGE is the elevation on this site; the window on it is
     flat, exactly as the product's is.
     Kept as a variable, and kept named --mk-lift, because every window in the
     kit already reads it and the ring is the part that was load-bearing: at
     --s1 on --bg, fill separation alone is not enough. */
  --mk-lift: 0 0 0 1px var(--line);
  --mk-lift-in: 0 0 0 1px var(--line);
  /* The product's own two shadows, both derived from --ink so they invert. */
  --mk-pane-shadow: -1px 0 4px -2px color-mix(in srgb, var(--ink) 14%, transparent);
  --mk-float: 0 12px 32px -18px color-mix(in srgb, var(--ink) 28%, transparent);

  color: var(--ink);
  line-height: 1.4;
}
[data-theme="dark"] .mk {
  /* Dark needs the stronger hairline, because --line at 7% white on #12161d is
     below the point where an edge reads at all. Still one ring, still no blur. */
  --mk-lift: 0 0 0 1px var(--line-2);
  --mk-lift-in: 0 0 0 1px var(--line-2);
}
.mk svg { flex: 0 0 auto }
/* The wordmark and the pixel logotype are aria-hidden art, so the accessible
   name has to be real text that is present but never painted. */
.mk-sr { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap }

/* --------------------------------------------------------------------------
   MK-Plate, the artifact stage. EVERY product view on the site sits on one,
   the hero included, and every one of them is the same OBJECT: the same shade,
   the same dot field, the same radius, the same hairline, and now the same
   HEIGHT. A mockup floating loose on the page background reads as page
   furniture; the same mockup on a framed, shaded stage reads as a thing being
   shown to you.

   The stage is three layers and no more:
     1. a soft vertical shade, 180deg, light at the top, hi -> mid -> lo
     2. a dot field on ::before, --plate-grid (12px) at --plate-dot (4.5% ink),
        edge to edge, UNMASKED
     3. one hairline at --line, plus a single top lip so the stage reads as a
        raised surface rather than a rectangle of fill

   Every one of those values is a --plate-* custom property declared once at the
   top of this file. A section that wants a different stage does not get one.

   ONE SHAPE, and this is the rule that answers "every mockup block on every
   page must be consistent". The stage is
   its window plus 2 x --plate-pad, and the window is 16:10 of whatever width
   its column gives it. It does not grow for a taller artifact and it does not
   shrink for a shorter one; it CROPS. Vertical centring plus overflow: clip
   means the artifact's own middle is what survives, which is the same contract
   .mk-crop offers horizontally.

   ONE WIDTH per column, not per block. The stage fills the column it is in, so
   the standard block runs the full artifact measure and an off-centred chapter
   block runs two thirds. What stays identical everywhere is the RATIO and the
   SCALE; a narrower column gets a proportionally shorter window, so both are
   the same shape at 1:1. A stage whose ratio changed per section is what made
   the below-fold read as unrelated screenshots.

   The stage always keeps all four of its edges. An artifact too big to fit does
   not get shrunk and does not get dissolved at the bottom by a mask: it goes
   inside a .mk-crop, which is the window, and the stage frames the window. A
   mask at the bottom edge removes the frame at exactly the edge that was meant
   to prove there is one.
   -------------------------------------------------------------------------- */
.mk-plate {
  position: relative; width: 100%; overflow: clip;
  /* The crop anchors below query THIS, not the viewport: the same artifact now
     appears at 1232 in a full-bleed stage and at 760 in a chapter column on the
     same page, so a viewport query cannot tell them apart. */
  container: mkstage / inline-size;
  display: flex; justify-content: center; align-items: center;
  padding: var(--plate-pad);
  background-color: var(--plate-mid);
  background-image: linear-gradient(180deg, var(--plate-hi) 0%, var(--plate-mid) 55%, var(--plate-lo) 100%);
  border: 1px solid var(--line); border-radius: var(--plate-r);
  box-shadow: inset 0 1px 0 var(--plate-lip);
}
/* The dot field is its own layer so it composites UNDER the artifact rather
   than inside the stage's own background stack, which is what lets the shade
   and the field be tuned independently. There is no mask on it: see the DOT
   block at the top of this file for the four measurements that killed the
   mask, and do not put one back. */
.mk-plate::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(var(--plate-dot) 1px, transparent 1px);
  background-size: var(--plate-grid) var(--plate-grid);
}
.mk-plate > * { position: relative; z-index: 1; flex: 0 0 auto; max-width: 100% }
/* THE ESCAPE HATCH, and it is a transition path rather than a variant. A plate
   that sizes to its child is a plate holding something that is not a crop, and
   the answer to that is almost always to take the component off the stage and
   put it in a card grid or beside its sentence. Until a block has been moved,
   .fit stops a 210-tall component from sitting in the middle of an empty stage,
   which is the exact defect the shared ratio exists to remove. Do not
   reach for it on anything the page calls a crop. */
.mk-plate.fit { height: auto }
/* The two-thirds stage. Kept because a standalone artifact outside a .chapter
   grid still has to line up with the ones inside it; its height comes from its
   own width at the shared ratio, like every other stage. */
.mk-plate.two-thirds { width: min(760px, 100%); margin-inline: auto }

/* --------------------------------------------------------------------------
   MK-CROP, THE WINDOW. It shows one rectangle of a bigger artifact at TRUE
   SCALE, so a crop is a region chosen and framed, never a whole panel shrunk.

   THE WINDOW IS 1232 x 770 at full measure, and its RATIO is declared once,
   here. Both of the owner's
   demands ("the same consistent size and height" and "clean, full-size,
   cropped, 1:1") only reconcile if the site fixes one window and then only
   picks regions that actually fill it. These are the measured numbers:

    1232  the width at which the dashboard's whole chrome fits: rail 240, the
          page's 36.96 gutter and an 918.09 table that does not overflow. It is
          also the Studio shell's own width. Below about 1199 the dashboard's
          identity column hits a 13rem floor and its card scrolls inside itself.
     770  1232 at 16:10. See the ratio note above: the height is derived, never
          chosen, so a chapter window at 676 is 422 and the same shape.

   HOW TO FRAME A CROP:
     1. Rebuild the region at the product's real sizes and put it inside
        .mk-crop as its ONLY child. It keeps its natural width and height; it
        is allowed, and expected, to be bigger than the window.
     2. Set the offset on the wrapper:
          --mk-crop-x   how far to pull the artifact LEFT, a positive px value
          --mk-crop-y   how far to pull it UP
        and only override the window itself if the region genuinely is narrower
        than 872, which is a reason to reconsider whether it is a crop at all:
          --mk-crop-w   visible width  (default 1232px, capped at the column)
        The height is not settable. It is --plate-ar of the width, because a
        window with a chosen height is how this file shipped a 2.2:1 letterbox.
     3. Nest it in a .mk-plate. The stage is already exactly tall enough.

   Example, a window onto the dashboard's Runs ledger rebuilt at 1:1, anchored
   so the card's top edge and all six rows land inside it:
     <div class="mk-crop" style="--mk-crop-x:0px;--mk-crop-y:13px">

   CHOOSE THE REGION FOR THE SENTENCE BESIDE IT. A crop earns its place by
   proving one claim: the ledger proves what a call cost, the graph proves the
   gate is in the graph, the rules table proves a limit is a row. A region that
   proves nothing in particular is a screenshot, and a screenshot is what the
   whole kit exists to avoid shipping.

   Never reach for transform: scale(). A scaled UI has fractional type and
   hairlines that land between device pixels, and that is exactly the tell the
   1:1 rule exists to avoid.
   -------------------------------------------------------------------------- */
.mk-crop {
  --mk-crop-w: min(1232px, 100%);
  --mk-crop-x: 0px; --mk-crop-y: 0px;
  position: relative; overflow: clip;
  width: var(--mk-crop-w); max-width: 100%; aspect-ratio: var(--plate-ar);
  /* THE WINDOW IS A WINDOW, so it is lifted off the stage rather than ruled
     onto it. This carried a 1px ring and no shadow for one release, on the
     reasoning that the product's own cards cast none. True, and beside the
     point: inside the app a card sits ON the page, while here a whole app sits
     ON a marketing page, and the thing that says so is elevation.

     The stack is the reference's, measured off cursor.com's hero window: a wide
     soft shadow, a tighter one under it, and a 1px ring last so the edge stays
     crisp on top of the blur. 10px of radius, not 20: at 20 a 1232px window
     reads as a rounded card, and at 10 it reads as a window. */
  background: var(--s1);
  border-radius: var(--mk-radius);
  box-shadow:
    0 28px 70px -12px color-mix(in srgb, var(--ink) 14%, transparent),
    0 14px 32px -12px color-mix(in srgb, var(--ink) 10%, transparent),
    0 0 0 1px var(--line);
}
/* The child is absolutely positioned so its own size cannot size the window,
   and the offset is applied as a negative inset rather than a transform, so
   nothing in the crop lands on a fractional pixel. */
.mk-crop > * { position: absolute; top: calc(-1 * var(--mk-crop-y)); left: calc(-1 * var(--mk-crop-x)) }
/* Inside a crop the WINDOW is the frame, so the artifact drops its own. Two
   hairlines a pixel apart along the top edge is a seam, and a 16px corner
   nested inside a 16px corner is a double bevel. The crop clips the artifact,
   so the artifact's own corners are never visible anyway. */
.mk-crop > * { box-shadow: none; border-radius: 0 }
/* The crop's own left edge is the origin, always. .mk-plate centres its child,
   and centring an OVERFLOWING child splits the negative free space in half, so
   an anchor calibrated against the left edge would land at half its value on
   top of a centring shift it was never measured against. The window is a
   block, not a flex item that can be centred by its own overflow. */
.mk-crop { margin-inline: auto }

/* THE STUDIO WINDOW. x is 0 at desktop, so the window opens on the rail and the
   reader sees the app: brand, workspace tree, the session bar, the chat, and the
   raised pane beside it. This offset was 256 for one release, the window opened
   PAST the rail, on the panes alone, and that is precisely how the hero stopped
   looking like Sapiom and started looking like a chat widget.

   It moves in ONE step per breakpoint rather than a ladder, because every
   in-between offset cuts a node title or half a wordmark, and half a lockup is
   worse than no lockup. */
@container mkstage (max-width: 900px) {
  /* The rail goes whole, at its own hairline, and the centre pane becomes the
     window. Same rule as the dashboard crops: a stripe of unreadable nav plus a
     cut pane is worse than the pane on its own. */
  .mk-crop.studio { --mk-crop-x: 256px }
}
/* Narrow crops keep the same top edge. Moving the shell upward on phones hid
   the workspace and session context and made the app appear vertically broken. */
@container mkstage (max-width: 620px) { .mk-crop.studio { --mk-crop-y: 0px } }

/* --------------------------------------------------------------------------
   MK-Window, the neutral frame. No traffic lights, no URL bar, no OS menu:
   a fake browser chrome is the oldest tell in marketing design, and we cannot
   verify a route on a gated app anyway.
   -------------------------------------------------------------------------- */
.mk-win {
  /* container-type on the rate table inside this frame applies inline-size
     containment, so the table can no longer size its own frame and the frame
     collapsed to 186px inside a 760px stage, clipping every price. The frame is
     a frame: it fills the stage it was given. */
  width: 100%;
  background: var(--s1); border-radius: var(--mk-radius);
  box-shadow: var(--mk-lift); overflow: hidden;
}
.mk-winbar {
  display: flex; align-items: center; gap: var(--sp2);
  min-height: var(--mk-bar); padding: 6px var(--mk-pad);
  border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: 12px; color: var(--ink-faint);
}
.mk-winbar .right { margin-left: auto; display: flex; align-items: center; gap: 6px }

/* --------------------------------------------------------------------------
   Tags, dots and the state row. A tag labels something the system knows; it is
   20px tall so it can never be mistaken for a 32px control, and it is a
   soft-rounded rect at --r-sm, not a capsule. A 20px capsule beside a 32px
   soft-rounded tab is two vocabularies for one idea, and the capsule is the one
   the product does not have.
   -------------------------------------------------------------------------- */
.mk-pill {
  display: inline-flex; align-items: center; gap: 4px;
  height: var(--mk-tag); padding: 0 8px; border: 0; border-radius: var(--r-sm);
  background: var(--active-shade); color: var(--ink-muted);
  font: 500 12px/1.2 var(--mono); letter-spacing: .01em; text-transform: lowercase;
  white-space: nowrap;
}
.mk-pill svg { width: 12px; height: 12px }
.mk-pill.num { font-variant-numeric: tabular-nums }

/* The state row: a dot plus a sentence-case word, and no tint. The app has no
   tinted status capsule, so neither does a product crop, and the word is what
   carries the state for a reader who cannot separate the hues. */
.mk-state { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink) }

.mk-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto }
.mk-dot.entry { background: var(--green) }
.mk-dot.step { border: 1px solid var(--ink-faint) }
.mk-dot.exit { background: var(--ink-faint) }
.mk-dot.warn { background: var(--amber) }
.mk-dot.live { background: var(--green) }

/* --------------------------------------------------------------------------
   MK-Shell, the agent.studio three-pane frame.

   Three background planes and no more: the rail and the centre pane are the
   FRAME at --bg, the right pane is the raised slab at --s1. The only chrome
   lines in the whole shell are two vertical hairlines and the right pane's
   left-edge shadow. The product draws no rule under any of its three 56px
   header bands, and adding them back is what turns one product into three
   panels sitting beside each other.

   Columns are the product's: the rail is pinned at its 256px floor, and what
   is left is split 1fr / 2fr between the centre pane and the right pane.
   -------------------------------------------------------------------------- */
/* THE SHELL IS THE WINDOW PLUS ITS OWN OFFSET. A shell at exactly 100% of the
   window is right only while --mk-crop-y is 0; the phone anchor drops the
   window 200px down the shell, and a 560-tall shell shifted up by 200 leaves
   199px of empty crop under it. Adding the offset back means the shell always
   reaches the window's bottom edge, at every anchor, with no per-breakpoint
   height to keep in sync. */
.mk-shell {
  position: relative; display: flex; width: 1232px; height: calc(100% + var(--mk-crop-y));
  background: var(--bg); border-radius: var(--mk-radius);
  box-shadow: var(--mk-lift); overflow: hidden;
}
.mk-shell .pane-rail {
  flex: 0 0 256px; min-width: 0; background: var(--bg);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
}
.mk-shell .pane-cli {
  flex: 1 1 0; min-width: 0; background: var(--bg);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
}
.mk-shell .pane-studio {
  flex: 2 2 0; min-width: 0; background: var(--s1);
  box-shadow: var(--mk-pane-shadow);
  display: flex; flex-direction: column;
}

/* One control recipe for every square button in the kit: 32px at 8px, and the
   only variant is the 28px dense one used inside a floating board bar. */
.mk-iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--mk-ctl); height: var(--mk-ctl); border-radius: var(--mk-r);
  border: 1px solid transparent; background: transparent; color: var(--ink-muted);
  cursor: pointer;
}
.mk-iconbtn svg { width: 14px; height: 14px }
/* The right pane runs its icons a size up; the rail and centre pane run 14. */
.mk-iconbtn.lg svg { width: 16px; height: 16px }
.mk-iconbtn.on { background: var(--active-shade); color: var(--ink) }
/* The one filled control in the whole shell. Deploy is the only irreversible
   action on the bar, so it is the only one that gets contrast. */
.mk-iconbtn.solid { background: var(--btn); color: var(--btn-ink); box-shadow: 0 1px 2px rgba(0,0,0,.05) }

/* --------------------------------------------------------------------------
   MK-Tab, THE tab. One declaration serves every tab row in the kit: the
   Canvas / Steps / Code row across the top of the right pane and the
   Activity / Plan / Results row across the top of the Steps table. Same 32px
   height, same 8px radius, same 14px type, same selected wash, same 4px gap.
   They used to be a 32px soft rect and a 40px capsule, which is what made the
   second row read as a control from a different product.

   Two selection mechanics, one look: .mk-tabs runs a travelling glider behind
   its tabs, so its selected tab paints no fill of its own, and a row without a
   glider paints the same --active-shade statically. At rest they are identical.
   -------------------------------------------------------------------------- */
.mk-tab, .mk-tabs .tab {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 4px;
  height: var(--mk-ctl); padding: 0 12px;
  border: 1px solid transparent; background: none; border-radius: var(--mk-r);
  font-family: var(--font); font-size: 14px; font-weight: 400; color: var(--ink-faint);
  white-space: nowrap; cursor: pointer;
}
.mk-tab svg, .mk-tabs .tab svg { width: 14px; height: 14px }
.mk-tab[aria-selected="true"], .mk-tab[aria-current="true"],
.mk-tabs .tab[aria-selected="true"] { color: var(--ink); font-weight: 500 }
/* A row with no glider paints the wash the glider would have parked there. */
.mk-tab[aria-selected="true"], .mk-tab[aria-current="true"] { background: var(--active-shade) }
@media (hover: hover) {
  .mk-tab:not([aria-selected="true"]):not([aria-current="true"]):hover {
    background: var(--hl); color: var(--ink);
  }
}
.mk-tab:focus-visible, .mk-tabs .tab:focus-visible { outline-color: var(--ink); outline-offset: -2px }
/* THE tab row: 4px gap, and the row itself is 32px of controls plus its own
   padding, never a taller band that makes the tabs look small inside it. */
/* flex: 0 0 auto on the tabs, so the ROW scrolls rather than the tabs
   shrinking below their nowrap labels and painting over the meta beside them. */
.mk-tabrow { display: flex; align-items: center; gap: 4px; min-width: 0; overflow-x: auto; scrollbar-width: none }
.mk-tabrow::-webkit-scrollbar { display: none }
.mk-tabrow > * { flex: 0 0 auto }

/* Shared product-window title bar. Marketing mockups use the same mark, mono
   product name, metadata alignment, and copy action instead of inventing a
   different header for every surface. */
.sapiom-ui-bar {
  position: relative; display: flex; align-items: center; gap: var(--sp3);
  flex: 0 0 auto; min-height: var(--header-h); padding: 0 var(--sp4);
  border-bottom: 1px solid var(--line); background: var(--s1); color: var(--ink-muted);
}
.sapiom-ui-brand {
  display: inline-flex; align-items: center; gap: var(--sp2); min-width: 0;
  font-family: var(--mono); font-size: var(--t-meta); color: var(--ink);
  white-space: nowrap;
}
.sapiom-ui-brand strong, .sapiom-ui-brand b { font-weight: 500 }
.sapiom-ui-brand img { width: 12px; height: 13px; flex: 0 0 auto; object-fit: contain }
[data-theme="dark"] .sapiom-ui-brand img { filter: invert(1) }
.sapiom-ui-bar > .meta {
  margin-left: auto; font-family: var(--mono); font-size: var(--t-meta);
  color: var(--ink-faint); white-space: nowrap;
}
.sapiom-ui-bar > .mk-copy { position: static; flex: 0 0 auto; margin-left: var(--sp1) }
.sapiom-ui-bar > .sapiom-ui-brand + .mk-copy { margin-left: auto }

/* ---- MK-Rail ------------------------------------------------------------ */
.mk-rail-head {
  display: flex; align-items: center; justify-content: space-between;
  height: var(--mk-head); padding: 0 8px 0 16px;
}
/* The lockup is the wordmark SVG in currentColor plus a mono product label.
   The word "Sapiom" is never set as text here and the S mark is never set
   beside it: the wordmark already is the name, and mark + name reads as a
   third logo that does not exist in the brand system. */
.mk-lockup { display: flex; align-items: center; font-size: 12px; line-height: 14.4px; white-space: nowrap; overflow: hidden }
.mk-lockup .logotype { height: 13px; width: auto; color: var(--ink); margin-bottom: -2.2px }
.mk-lockup .product {
  margin-left: 8px; font-family: var(--mono); font-size: 12px; font-weight: 500;
  letter-spacing: .06em; color: var(--ink-muted);
}
.mk-rail-nav { padding: 12px 8px 0; display: flex; flex-direction: column; gap: var(--sp0) }
.mk-nav-row {
  display: flex; align-items: center; gap: 8px; width: 100%;
  height: var(--mk-ctl); padding: 0 8px;
  border: 0; background: transparent; border-radius: var(--mk-r);
  font-family: var(--font); font-size: 14px; color: var(--ink-muted); text-align: left;
}
.mk-nav-row svg { width: 14px; height: 14px }
.mk-nav-row .kbd { margin-left: auto; font-family: var(--mono); font-size: 12px; color: var(--ink-faint) }
/* The Workspaces band is one row: the label, its caret, and two 32px actions.
   Hover fills the whole row, never just the toggle. */
.mk-rail-section { display: flex; align-items: center; gap: 8px; height: var(--mk-ctl-lg); padding: 0 8px; border-radius: var(--mk-r) }
.mk-rail-section .mk-nav-row { flex: 1; min-width: 0 }
.mk-rail-section .acts { display: flex; align-items: center }
.mk-rail-tree { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; gap: 10px; padding: 4px 8px 0 }
.mk-workspace { display: flex; flex-direction: column; gap: var(--sp0) }
.mk-tree-row {
  display: flex; align-items: center; gap: 8px; height: var(--mk-ctl); padding: 0 8px;
  border: 0; background: transparent; border-radius: var(--mk-r);
  font-family: var(--font); font-size: 14px; color: var(--ink-muted); text-align: left;
}
/* An agent row carries no leading glyph. The 32px indent is the hierarchy. */
.mk-tree-row.nested { padding-left: 32px }
.mk-tree-row svg { width: 14px; height: 14px; color: var(--ink-muted) }
.mk-tree-row .nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
/* A fixed 16px slot, so a row with a lifecycle glyph and a row without it put
   their labels in the same place. */
.mk-tree-row .trail { display: inline-flex; align-items: center; justify-content: center; width: 16px; color: var(--ink-muted) }
.mk-tree-row .caret { display: inline-flex; transition: transform var(--fast) var(--ease) }
.mk-tree-row .caret.shut { transform: rotate(-90deg) }
/* Selection is a fill on the row, never a side bar and never an accent. The
   selected label is the only one at full ink and weight 500. */
.mk-tree-row[aria-current="true"] { background: var(--active-shade); color: var(--ink) }
.mk-tree-row[aria-current="true"] .nm { font-weight: 500 }

.mk-rail-foot { margin-top: auto; padding: 8px 16px 12px }
.mk-profile { display: flex; align-items: center; gap: 8px; min-height: var(--mk-head) }
.mk-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%; background: var(--s3);
  font-size: 12px; font-weight: 500; color: var(--ink-muted);
}
/* The product's account avatar is a tile, not a circle: it sits in a column of
   8px-radius rows and a lone circle breaks the column. */
.mk-avatar.tile {
  width: 32px; height: 32px; border-radius: var(--mk-r);
  background: var(--active-shade); border: 1px solid var(--line);
  font-size: 14px; font-weight: 600; color: var(--ink);
}
.mk-profile .who { display: flex; flex-direction: column; min-width: 0; gap: 1px }
.mk-profile .who b { font-size: 14px; font-weight: 400; color: var(--ink-faint) }
.mk-profile .who span { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-faint) }
.mk-profile .who span i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 auto }
.mk-profile > svg { margin-left: auto; width: 14px; height: 14px; color: var(--ink-muted) }

/* ---- MK-SessionBar ------------------------------------------------------ */
.mk-session { display: flex; align-items: center; gap: 8px; height: var(--mk-head); padding: 0 16px }
.mk-session .title {
  display: inline-flex; align-items: center; gap: 4px; height: var(--mk-ctl); padding: 0 4px;
  border: 0; background: transparent; border-radius: var(--mk-r); min-width: 0;
}
.mk-session .title b { font-family: var(--font); font-size: 14px; font-weight: 500; color: var(--ink) }
.mk-session .title svg { width: 12px; height: 12px; color: var(--ink-faint) }
.mk-session .acts { margin-left: auto; display: flex; align-items: center; gap: 4px }
.mk-session .studio-session-action {
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--mk-ctl); padding-inline: var(--sp2);
  border: 1px solid var(--line-2); border-radius: var(--mk-r);
  background: var(--s1); color: var(--ink);
  font-family: var(--mono); font-size: var(--t-meta); line-height: 1;
  white-space: nowrap;
}
.mk-session .studio-session-action.is-primary {
  border-color: var(--btn); background: var(--btn); color: var(--btn-ink);
}

/* --------------------------------------------------------------------------
   MK-Boot, the terminal pane's masthead. A ruled box, not loose lines: the
   version legend is punched into the top edge the way a fieldset legend is, so
   the card is defined by its 1px border alone and needs no fill.
   -------------------------------------------------------------------------- */
/* One card, two layouts. Below 560px the brand block stacks over the facts and
   its divider becomes the rule between them; that is the form the product
   shows at a one-third centre pane, so it is the form a narrow crop must use. */
@container boot (max-width: 560px) {
  .mk-boot { flex-direction: column; align-items: stretch; gap: 12px }
  .mk-boot .brand { align-self: auto; padding: 0 0 12px; border-right: 0; border-bottom: 1px solid var(--line) }
}
@container boot (max-width: 200px) { .mk-boot .brand .mark { display: none } }

/* --------------------------------------------------------------------------
   MK-Chat, the Studio's assistant panel, and the panel the Studio crop shows.
   The terminal is a real surface but it is the DEVELOPER surface; the chat
   panel is the one a first-time reader recognises, and it is what the product
   opens on. It is the same three planes and the same 8px product radius as the
   rest of the shell, so it reads as one application rather than a widget.

   Its anatomy, top to bottom, and every part of it is a real part:
     .mk-chat-feed        top-anchored, scrolls under a soft top fade
       .mk-msg.you        the human's turn, full ink, no bubble
       .mk-msg.think      "Thought for 7s", mono, the quietest line on the panel
       .mk-msg.tool       a tool result, mono, with the tool name at full ink
       .mk-chat-steps     the inline step card, rows of "01 intake records.read"
       .mk-chat-meta      a row of 20px tags
       .mk-answer         a titled answer block with a bold "Next action:" lead
       .mk-outcome        an outcome card, a green check and a mono meta line
     .mk-chat-sugg        the starter row: 32px rects, ONE side-scrolling line
     .mk-chat-composer    the composer, anchored at the bottom
   and nothing under the composer. The reassurance line is gone; see the note
   on .mk-chat-note.

   There are no bubbles and no avatars. The product renders a turn as a block of
   text with a marker, and a bubbled chat is the tell that a mockup was drawn
   from a consumer messenger rather than from the app.
   -------------------------------------------------------------------------- */
.mk-chat {
  display: flex; flex-direction: column; min-width: 0; min-height: 0; width: 100%;
  container: mkchat / inline-size;
  /* An inner card sits one step off whatever the panel is: --s2 on a raised
     card, --s1 inside the shell where the pane itself is --bg. */
  --chat-inset: var(--s2);
  /* A cut edge on the feed says which way the conversation carries on. The
     top-anchored panel opens on the first turn and dissolves at the BOTTOM; the
     panel in the shell is scrolled to the newest turn and dissolves at the TOP.
     At 0px the stop collapses and that end is a hard edge. */
  --chat-fade-top: 0px;
  --chat-fade-bot: var(--sp5);
  background: var(--s1); border: 1px solid var(--line);
  border-radius: var(--mk-radius); box-shadow: var(--mk-lift); overflow: hidden;
}
/* Inside the shell the pane already owns the frame, the fill and the hairline,
   so the panel adds none of its own. */
.mk-chat.flat {
  flex: 1 1 auto; --chat-inset: var(--s1);
  --chat-fade-top: 0px; --chat-fade-bot: var(--sp5);
  background: transparent; border: 0; border-radius: 0; box-shadow: none;
}
/* Standalone, the panel is an ARTIFACT, so it is exactly as tall as every other
   artifact on the site: --panel-h. It used to size to its conversation
   between a 420 floor and a 640 ceiling, which meant the one block on the page
   whose height was decided by how much copy the fixture happened to carry. The
   feed gets whatever is left after the starter row and the composer, roughly
   300px, and past that it is cut and the top fade says so. */
.mk-chat.tall { height: var(--panel-h) }

.mk-chat-feed {
  flex: 1 1 auto; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start;
  gap: var(--sp3); padding: var(--sp4) var(--sp4) var(--sp3);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, black var(--chat-fade-top),
    black calc(100% - var(--chat-fade-bot)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, black var(--chat-fade-top),
    black calc(100% - var(--chat-fade-bot)), transparent 100%);
}
.mk-chat-feed > * { flex: 0 0 auto; min-width: 0 }
/* Every conversation begins at the top of its pane. The feed takes the
   remaining height, so the composer is the only element that stays at the
   bottom without any absolute positioning. */
.mk-chat.flat .mk-chat-feed { justify-content: flex-start }

/* margin: 0 because a turn is a <p> and the feed owns the vertical rhythm. A UA
   1em margin here adds 28px between every turn on top of the flex gap, which is
   what pushed the step card out of the pane. */
.mk-msg { margin: 0; font-size: 14px; line-height: 1.5; min-width: 0; overflow-wrap: break-word }
.mk-msg.you { color: var(--ink); font-weight: 500 }
.mk-msg.think, .mk-msg.tool { font-family: var(--mono); font-size: 12px; line-height: 1.5; color: var(--ink-faint) }
.mk-msg.tool { color: var(--ink-muted) }
.mk-msg.tool b { font-weight: 500; color: var(--ink) }

/* The inline step card. Four tracks, subgrid rows, and the chevron gets a fixed
   track so every row's arrow lands on one axis. */
.mk-chat-steps {
  display: grid;
  grid-template-columns: var(--sp1) max-content minmax(0, 1fr) max-content var(--sp4) var(--sp1);
  column-gap: var(--sp2);
  border: 1px solid var(--line); border-radius: var(--mk-r); overflow: hidden;
}
.mk-chat-steps > * {
  display: grid; grid-column: 1 / -1; grid-template-columns: subgrid;
  align-items: center; min-height: var(--row-h-xs);
}
/* Gutter tracks, not row padding, for the reason spelled out on .mk-step. */
.mk-chat-steps > *::before, .mk-chat-steps > *::after { content: "" }
.mk-chat-steps > * + * { border-top: 1px solid var(--line) }
.mk-chat-steps .ord { font-family: var(--mono); font-size: 12px; color: var(--ink-faint); font-variant-numeric: tabular-nums }
.mk-chat-steps .nm { font-family: var(--mono); font-size: 13px; color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mk-chat-steps .cap { font-family: var(--mono); font-size: 12px; color: var(--ink-muted); white-space: nowrap }
.mk-chat-steps svg { width: 14px; height: 14px; color: var(--ink-faint); justify-self: end }

.mk-chat-meta { display: flex; flex-wrap: wrap; gap: var(--sp1) }

/* The answer block. A title, a paragraph, and a bold lead-in on the sentence
   that says what to do next. The lead-in is weight, not colour, because colour
   on this site means state and a recommendation is not a state. */
.mk-answer { display: flex; flex-direction: column; gap: var(--sp2); min-width: 0 }
.mk-answer .ttl { font-size: 14px; font-weight: 600; line-height: 1.4; color: var(--ink) }
.mk-answer p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--ink) }
.mk-answer p b { font-weight: 600 }

/* An outcome card: the check carries the state and the check SHAPE repeats it,
   so the green is never load-bearing. No fill, one hairline, same 8px radius as
   every other card nested in a framed window. */
.mk-outcome {
  display: grid; grid-template-columns: var(--sp4) minmax(0, 1fr);
  align-items: start; gap: var(--sp2);
  padding: var(--sp3); border: 1px solid var(--line); border-radius: var(--mk-r);
}
.mk-outcome > svg { width: 14px; height: 14px; margin-top: 3px; color: var(--green-text) }
.mk-outcome > :not(svg) { grid-column: 2 }
.mk-outcome b { font-size: 13px; font-weight: 600; line-height: 1.4; color: var(--ink) }
.mk-outcome p { margin: 0; font-size: 13px; line-height: 1.5; color: var(--ink-muted) }
.mk-outcome .fx { font-family: var(--mono); font-size: 12px; color: var(--ink-faint) }

/* THE STARTER ROW. ONE row, always, and it side-scrolls.
   --------------------------------------------------------------------------
   It used to have a .two variant that wrapped to two lines. Two lines is what
   made the row read as a second surface stacked under the panel instead of as
   part of it: a wrapped row has a block of its own with a top and a bottom
   edge, and the eye reads any block above a composer as a tray. One row that
   runs off the right edge reads as what it is, a rail of starters with more
   past the fold, and it costs the panel 32px instead of 72.

   NO FILL OF ITS OWN, on the row or under it. The row is transparent and sits
   directly on the panel's backdrop; the chips are a hairline and nothing else.
   Anything with a background here paints a second shade inside a panel that
   already has one, which is the "reads as a second surface" complaint.

   The fade at the right edge is the one gradient in the kit that means "this
   carries on past here", and it is 48px so it reads as a dissolve rather than
   as a chip that happens to be cut. flex: 0 0 auto on the chips, so the ROW
   scrolls rather than the chips squeezing below their nowrap labels. */
.mk-chat-sugg {
  display: flex; flex-wrap: nowrap; gap: var(--sp2);
  padding: 0 var(--sp4) var(--sp2); margin-bottom: var(--sp1);
  background: none;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  -webkit-mask-image: linear-gradient(to right, black 0, black calc(100% - 48px), transparent);
          mask-image: linear-gradient(to right, black 0, black calc(100% - 48px), transparent);
}
.mk-chat-sugg::-webkit-scrollbar { display: none }
.mk-chat-sugg > * { flex: 0 0 auto }
.mk-sugg {
  flex: 0 0 auto; display: inline-flex; align-items: center;
  height: var(--mk-ctl); padding: 0 var(--sp3);
  background: transparent; border: 1px solid var(--line); border-radius: var(--mk-r);
  font-family: var(--font); font-size: 13px; color: var(--ink-muted);
  white-space: nowrap; cursor: pointer;
}

/* The composer. One step lighter than the panel behind it, one hairline, 8px,
   and a 54px text well so it reads as a place to write a paragraph rather than
   a search box. */
.mk-chat-composer {
  display: flex; flex-direction: column; margin: 0 var(--sp4) var(--sp2);
  background: var(--chat-inset); border: 1px solid var(--line); border-radius: var(--mk-r);
}
.mk-chat-composer .ph {
  padding: var(--sp3) var(--sp3) var(--sp2); min-height: 54px;
  font-size: 14px; line-height: 20px; color: var(--ink-faint);
}
.mk-chat-composer .foot { display: flex; align-items: center; gap: var(--sp1); padding: 0 var(--sp2) var(--sp2) }
.mk-chat-composer .foot .mk-iconbtn { color: var(--ink-faint) }
/* Submit is the one filled control on the panel, and it is a soft-rounded
   square at THE control size, not a capsule: nothing else on this site is a
   capsule, and one round button is enough to make the panel look borrowed. */
.mk-chat-composer .go {
  margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
  width: var(--mk-ctl); height: var(--mk-ctl); padding: 0;
  border: 0; border-radius: var(--mk-r);
  background: var(--btn); color: var(--btn-ink); cursor: pointer;
}
.mk-chat-composer .go svg { width: 15px; height: 15px }
/* THE REASSURANCE LINE IS GONE. "Nothing runs or deploys until you say so."
   was a promise the composer already makes by having a submit button, and a
   12px caption under a control is the shape of a disclaimer: it reads as the
   product hedging. display: none rather than deleting the rule, because the
   markup on two pages still carries the <p> and an unstyled paragraph would
   ship the sentence back at body size with UA margins. Remove the element from
   the pages and this rule goes with it. */
.mk-chat-note { display: none }
/* At a one-third pane the composer keeps its well and gives back side padding
   before it gives back the well: a 32px text area stops looking like a place to
   describe an outcome. */
@container mkchat (max-width: 340px) {
  .mk-chat-feed, .mk-chat-sugg { padding-inline: var(--sp3) }
  .mk-chat-composer { margin-inline: var(--sp3) }
  /* Same rule the Steps table runs: narrow DROPS a column rather than
     ellipsing every name. A card of "collect-so… / read-sourc… / publish-di…"
     is six rows the reader cannot name, and the capability is the cell they can
     afford to lose, because the step id is the thing being listed. */
  .mk-chat-steps { grid-template-columns: var(--sp1) max-content minmax(0, 1fr) var(--sp4) var(--sp1) }
  .mk-chat-steps .cap { display: none }
}

/* --------------------------------------------------------------------------
   MK-Terminal. It FOLLOWS THE THEME, because the product's does: xterm reads
   --bg for its background and --ink for its foreground at call time, so a
   theme toggle re-themes the buffer in place. A terminal pinned to #15161c is
   a black slab on a light page that belongs to no theme, and it was the whole
   of the "panels do not map light cleanly" defect.

   The three ANSI hues below are the product's exact xterm palette entries, and
   they are the only literal hex in this file. They cannot be tokens: xterm
   ships a fixed 16-colour table and the app hands it these values per theme,
   so the mockup has to quote them to match the buffer it is imitating.

   The terminal is the developer view and it lives on /developers/ and in the
   install tabs. The Studio crop shows .mk-chat instead.
   -------------------------------------------------------------------------- */
.mk-term {
  background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--mk-radius); overflow: hidden;
}
.mk-termbar {
  display: flex; align-items: center; gap: 6px; height: var(--mk-bar); padding: 0 12px;
  border-bottom: 1px solid var(--line);
}
.mk-termbar em { margin-left: 6px; font-style: normal; font-family: var(--mono); font-size: 12px; color: var(--ink-faint) }
.mk-term pre {
  margin: 0; padding: 16px; overflow: hidden;
  font-family: var(--mono); font-size: 13px; line-height: 17px; letter-spacing: -0.0125px;
  color: var(--ink); white-space: pre-wrap; word-break: break-word;
}
/* The prompt glyph and a tool name are the buffer's only bold runs. */
/* The assistant bullet. ANSI 2 in the app's table: #16a34a light, #4ade80 dark. */
.mk-term i { font-style: normal; color: #16a34a }
[data-theme="dark"] .mk-term i { color: #4ade80 }
.mk-term .u { color: var(--ink) }        /* what the human typed  */
.mk-term .o { color: var(--ink-muted) }  /* tool output           */
.mk-term .ok { color: #15803d }          /* a green result, 4.8:1 */
[data-theme="dark"] .mk-term .ok { color: #4ade80 }
.mk-caret { display: inline-block; width: 7px; height: 13px; vertical-align: -2px; background: var(--green); animation: mk-blink 2s cubic-bezier(.4, 0, .6, 1) infinite }
@keyframes mk-blink { 0%, 45% { opacity: 1 } 55%, 100% { opacity: 0 } }
@media (prefers-reduced-motion: reduce) { .mk-caret { animation: none } }

/* --------------------------------------------------------------------------
   MK-TabRow. Selection is a travelling pill behind the tabs; the active tab
   changes ink weight only, so nothing jumps when the pill moves. No rule under
   the row: the right pane is one unbroken shade from here to the sheet.
   -------------------------------------------------------------------------- */
.mk-tabs {
  position: relative; display: flex; align-items: center; gap: 4px;
  height: var(--mk-head); padding: 0 16px;
}
/* A tablist may only own tabs, and .mk-tabs also holds the glider and the
   control cluster, so the three tabs get their own wrapper. It stays
   unpositioned on purpose: the glider measures offsetLeft against .mk-tabs.
   The tabs themselves are declared once, in the .mk-tab block above. */
.mk-tabs .tabset { display: flex; align-items: center; gap: 4px }
.mk-tabs .glider {
  position: absolute; z-index: 0; top: 50%; left: 0; height: var(--mk-ctl);
  margin-top: calc(var(--mk-ctl) / -2);
  border-radius: var(--mk-r); background: var(--active-shade);
  transition: transform .22s var(--ease), width .22s var(--ease);
}
@media (prefers-reduced-motion: reduce) { .mk-tabs .glider { transition: none } }
.mk-tabs .right { margin-left: auto; display: flex; align-items: center; gap: 4px; flex-shrink: 0 }
/* The three projections of the bound agent. All three are in the DOM: a tab
   that moves a glider over nothing is worse than no tab at all. */
.mk-panes { flex: 1; min-height: 0; display: flex; flex-direction: column }
.mk-panes > * { flex: 1; min-height: 0; display: flex; flex-direction: column }
.mk-panes > [hidden] { display: none }
.mk-pane-scroll { flex: 1; min-height: 0; overflow: hidden; padding: 16px }

/* --------------------------------------------------------------------------
   MK-Board, the canvas cascade. The most photogenic object the product has.
   The graph is pinned by its CENTRE, so it sits dead centre of the board at
   any board size, the way the product's zoom-to-centre does. The 16px dot
   lattice belongs to the board and does not move with the graph.
   -------------------------------------------------------------------------- */
/* The board's own lattice is NOT the stage's. The product keeps two grids on
   purpose: the shared 12px / 22% one the dashboard's flow canvas paints (which
   is what --plate-dot now is), and the Studio board's own 16px / 10% duplicate
   in sapiom-studio/public/canvas/board/board.css, which exists because an
   iframe cannot inherit a custom property. This rule quotes the board's copy,
   measured: light rgb(230,230,231) on #ffffff, dark rgb(39,43,49) on #12161d.
   Do not unify them. Two planes at two pitches is the product's own answer to
   a canvas sitting on a page that also has a grid. */
.mk-board {
  position: relative; flex: 1; min-height: 0; overflow: hidden; padding: 56px;
  background-image: radial-gradient(color-mix(in srgb, var(--ink) 10%, transparent) 1px, transparent 1px);
  background-size: 16px 16px;
}
.mk-cascade { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center }
.mk-node {
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  min-width: 160px; padding: 10px 12px; text-align: left;
  background: var(--s1); border: 1px solid var(--line); border-radius: var(--mk-r);
  box-shadow: 0 1px 2px rgb(0 0 0 / .04);
}
.mk-node .nm { font-size: 12px; font-weight: 520; line-height: 1.25; color: var(--ink) }
/* kind left, structural facts right. There is no coloured dot inside a node:
   the kind is a word, and a dot repeating it is a second vocabulary. */
.mk-node .fx { display: flex; align-items: center; gap: 6px; font: 500 10px/1.2 var(--mono); color: var(--ink-faint) }
.mk-node .fx .kind { flex: 0 0 auto }
.mk-node .fx .facts { flex: 1 1 auto; text-align: right }
.mk-group {
  position: relative; display: flex; flex-direction: column; align-items: center;
  padding: 20px 16px 12px; min-width: 184px;
  border: 1px solid var(--line); border-radius: var(--mk-r);
}
.mk-group > .mk-caps {
  position: absolute; top: -10px; left: 12px;
  min-height: var(--mk-tag); padding: 0 8px; display: inline-flex; align-items: center;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--s1);
  font: 500 10px/1 var(--mono); color: var(--ink-faint);
}
/* Edge: a hairline bar with a CSS-triangle head. An SVG per edge is a lot of
   nodes for a shape this simple. */
.mk-edge { position: relative; width: 1px; height: 18px; background: var(--line-2); opacity: .9; flex-shrink: 0 }
.mk-edge::after {
  content: ""; position: absolute; left: -2px; bottom: 0;
  border: 2.5px solid transparent; border-top: 3.5px solid var(--ink-faint);
}
/* The fork arms land at x 74 and x 246 of a 320-unit row, so the outcomes row
   is 320 wide with a 24 gap and nothing else. Widening it moves every node off
   the arm that points at it. */
.mk-fork, .mk-outcomes { width: 524px; flex-shrink: 0 }
.mk-fork { position: relative; height: 44px }
.mk-fork svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block }
.mk-fork path { fill: none; stroke: var(--line-2); stroke-linecap: round }
.mk-fork .lbl {
  position: absolute; top: 8px; transform: translateX(-50%);
  min-height: var(--mk-tag); padding: 0 8px; display: inline-flex; align-items: center;
  border-radius: var(--r-sm); background: var(--s1); border: 1px solid var(--line);
  font: 500 10px/1 var(--mono); color: var(--ink-faint); white-space: nowrap;
}
.mk-outcomes { display: grid; grid-template-columns: repeat(2, 250px); gap: 24px; justify-items: center }

/* Two floating cards over the board, one recipe. They are what make the board
   read as a canvas rather than as a diagram. */
.mk-boardbar {
  position: absolute; bottom: 12px; z-index: 3;
  display: flex; align-items: center; gap: 4px; padding: 4px;
  background: var(--s1); border: 1px solid var(--line);
  border-radius: var(--mk-r); box-shadow: var(--mk-float);
}
.mk-boardbar.zoom { left: 12px }
.mk-boardbar.tools { right: 12px }
.mk-boardbar .pct {
  display: inline-flex; align-items: center; height: var(--mk-ctl); padding: 0 8px;
  border: 0; background: transparent; border-radius: var(--mk-r);
  font-family: var(--mono); font-size: 12px; color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   MK-Overview, the sheet docked under the board. Same shade as the board, one
   hairline between them, and a legend that is the only colour on the tab.

   The sheet is the bottom of the whole shell, so its inner bottom padding is
   the only thing between the last line of the summary and the window's edge.
   It runs 48px, deliberately larger than the 16px at the sides: a sheet that
   ends 16px under its last bullet reads as content that got cut off, and it is
   the one measurement a reader registers as unfinished. Rows inside it are
   16px apart rather than 12, because they are separate thoughts.
   -------------------------------------------------------------------------- */
.mk-overview { position: relative; flex: 0 0 auto; border-top: 1px solid var(--line); background: var(--s1); overflow: hidden }
.mk-overview .head { display: flex; align-items: center; gap: 8px; height: var(--mk-head); padding: 0 16px; font-size: 14px; font-weight: 500; color: var(--ink) }
.mk-overview .head > svg { width: 14px; height: 14px; color: var(--ink-faint) }
.mk-overview .head .right { margin-left: auto; display: flex; align-items: center; flex-wrap: wrap; gap: 4px }
.mk-overview .body {
  display: flex; flex-direction: column; gap: var(--sp4);
  padding: var(--sp3) var(--sp4) var(--sp7);
  font-size: 14px; line-height: 1.55; color: var(--ink-muted);
}
.mk-overview .body p { margin: 0; color: var(--ink) }
.mk-overview .body ul { margin: 0; padding-left: var(--sp4); display: flex; flex-direction: column; gap: var(--sp2) }
.mk-overview .body li { color: var(--ink-muted) }
.mk-legend { display: flex; align-items: center; gap: 12px; font-size: 12px; color: var(--ink-faint) }
.mk-legend span { display: inline-flex; align-items: center; gap: 6px }
.studio-overview .head { height: var(--row-h-sm); font-size: var(--t-small) }
.studio-overview .body {
  display: flex; flex-direction: column; align-items: stretch;
  gap: var(--sp2); padding: var(--sp2) var(--sp4) var(--sp3);
  font-size: var(--t-meta); line-height: 1.45;
}
.studio-overview .body p {
  display: -webkit-box; min-width: 0; overflow: hidden;
  -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  white-space: normal;
}
.studio-overview .mk-legend { white-space: nowrap }

/* --------------------------------------------------------------------------
   MK-Steps, the run step list, and it is a TABLE.

   Six columns, one row per step, and nothing stacks at any width:
     .ord    the ordinal, mono, tabular
     .st     the status glyph
     .nm     the humanised step title
     .cap    the capability, mono
     .dur    the duration, mono, right
     .cost   what the step cost, mono, right

   One grid owns the tracks and the header row and every step row take SUBGRID
   from it, which is the only way cells actually line up once a title runs long.
   Two separate grids, or a row that lays out its own two-line stack, is what
   made the old list read as six cards rather than as a run.

   Narrow does not mean stacked. Below the width where six tracks fit, the table
   DROPS a column, in the order duration, capability, ordinal, and every
   surviving row is still one row. A step whose duration folded under its title
   is a row the reader has to reassemble, and the app never draws it.
   -------------------------------------------------------------------------- */
/* .mk-steps is the CARD and the query container; .mk-steps-grid is the grid.
   The wrapper is not decoration: a container query cannot match the container
   itself, so the element that reads the width and the element that owns the
   tracks have to be two elements, or the column drops below can only ever hide
   cells and would leave their empty tracks standing. */
.mk-steps {
  width: min(760px, 100%); container: mksteps / inline-size;
  background: var(--s1); border: 1px solid var(--line); border-radius: var(--mk-radius);
  overflow: hidden;
}
.mk-steps-grid {
  --steps-cols: max-content max-content minmax(5rem, 1fr) minmax(6rem, 1.05fr) max-content max-content;
  --steps-gutter: var(--sp1);
  display: grid;
  grid-template-columns: var(--steps-gutter) var(--steps-cols) var(--steps-gutter);
  column-gap: var(--sp3);
}
/* The toolbar spans every track: it is chrome above the table, not a row in it.
   Its 4px inset plus a tab's own 12px padding lands the first tab's label on
   the same axis as the first column below it. */
.mk-steps-bar {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 4px;
  min-height: var(--mk-head); padding: var(--sp2) var(--sp1);
  border-bottom: 1px solid var(--line);
}
/* The run id and its total are a fact line, not two tinted capsules. */
.mk-steps-bar .meta { margin-left: auto; padding-inline: var(--sp3) var(--sp4) }
.mk-steps-cols, .mk-step {
  grid-column: 1 / -1; display: grid; grid-template-columns: subgrid;
  align-items: center;
}
/* THE ROW INSET IS TWO EMPTY GUTTER TRACKS, never padding on the row. A subgrid
   still resolves its tracks from the parent, so padding on it is added on top of
   those tracks and pushes the last column off the right edge, which is the exact
   defect the old rules table papered over with a spacer column. The generated
   boxes are grid items and fill the gutters by auto-placement, so dropping a
   column cannot shift the inset. 4px plus the 12px gap is the 16px every other
   surface in the shell runs on. */
.mk-steps-cols::before, .mk-steps-cols::after,
.mk-step::before, .mk-step::after { content: "" }
.mk-steps-cols {
  min-height: var(--control-h-sm);
  border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: .04em; color: var(--ink-faint); text-transform: lowercase;
}
.mk-step { min-height: var(--row-h-sm) }
.mk-step + .mk-step { border-top: 1px solid var(--line) }
/* Header cells sit on the same tracks as their values, so they take the same
   alignment: a right-aligned numeral under a left-aligned label reads as two
   columns rather than one. */
.mk-steps-cols .dur, .mk-steps-cols .cost, .mk-step .dur, .mk-step .cost { text-align: right }
.mk-step .ord, .mk-steps-cols .ord { font-family: var(--mono); font-size: 12px; color: var(--ink-faint); font-variant-numeric: tabular-nums }
/* Sentence case, humanised. The app renders a step id as a title, so a raw
   kebab id in the title slot is a row the app never draws. */
.mk-step .nm { font-size: 13px; font-weight: 500; line-height: 1.35; color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mk-step .cap { font-family: var(--mono); font-size: 12px; color: var(--ink-muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mk-step .dur { font-family: var(--mono); font-size: 12px; color: var(--ink-muted); white-space: nowrap; font-variant-numeric: tabular-nums }
.mk-step .cost { font-family: var(--mono); font-size: 12px; color: var(--ink); white-space: nowrap; font-variant-numeric: tabular-nums }
.mk-step[data-state="pending"] .nm, .mk-step[data-state="pending"] .cost { color: var(--ink-muted) }
.mk-step[data-state="pending"] .cap, .mk-step[data-state="pending"] .dur { color: var(--ink-faint) }

/* The status glyph: a 32px ringed, tinted disc carrying the CAPABILITY icon,
   with a state badge bottom-right. The ring, the fill and the badge shape all
   repeat the state, so the tint is never load-bearing.

   This disc and its badge are two of the three sanctioned circles in the kit
   (the third is the account avatar). Everything else is a soft-rounded rect. */
.mk-status {
  --st-ink: var(--ink-faint); --st-line: var(--line); --st-fill: var(--s2);
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 999px;
  border: 1px solid var(--st-line); background: var(--st-fill); color: var(--st-ink);
}
.mk-status > svg { width: 14.4px; height: 14.4px }
.mk-status .badge {
  position: absolute; right: -3.2px; bottom: -2.4px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 14.4px; height: 14.4px; border-radius: 999px;
  border: 1px solid var(--st-line); background: var(--s1); color: var(--st-ink);
}
.mk-status .badge svg { width: 9.6px; height: 9.6px }
.mk-status.pass { --st-ink: var(--green-text); --st-line: color-mix(in srgb, var(--green) 30%, transparent); --st-fill: color-mix(in srgb, var(--green) 10%, var(--s1)) }
.mk-status.idle { --st-ink: var(--ink-faint); --st-line: var(--line); --st-fill: var(--s2) }

/* Column drops, in order of what a reader can lose and still read the run. The
   cost never drops: a step list that loses its cost column is showing the
   reader everything except the answer. */
@container mksteps (max-width: 540px) {
  .mk-steps-grid { --steps-cols: max-content max-content minmax(5rem, 1fr) minmax(6rem, 1.05fr) max-content }
  .mk-steps .dur { display: none }
}
@container mksteps (max-width: 430px) {
  .mk-steps-grid { --steps-cols: max-content max-content minmax(5rem, 1fr) max-content; --steps-gutter: 0px }
  .mk-steps .cap { display: none }
}
@container mksteps (max-width: 330px) {
  .mk-steps-grid { --steps-cols: max-content minmax(4rem, 1fr) max-content }
  .mk-steps .ord { display: none }
}

/* MK-Receipt, the payload alone on the page with no frame around it. */
.mk-receipt {
  width: min(640px, 100%); margin-inline: auto; padding: 20px 22px;
  background: var(--s1); border: 1px solid var(--line); border-radius: var(--r-xl);
  box-shadow: var(--mk-lift);
  font-family: var(--mono); font-size: 12.5px; line-height: 1.75;
  color: var(--ink-muted); white-space: pre;
  overflow-x: auto;
}
.mk-receipt .k { color: var(--ink) }
.mk-receipt .n { color: var(--ink); font-weight: 500 }

/* --------------------------------------------------------------------------
   MK-Gantt, the planned sequence. The amber wait span is the whole argument
   for durable execution, so it needs no other decoration.
   -------------------------------------------------------------------------- */
.mk-gantt { width: min(700px, 100%); background: var(--s1); border: 1px solid var(--line); border-radius: var(--r-xl); box-shadow: var(--mk-lift); padding: 18px 20px }
.mk-gantt-head { display: flex; align-items: baseline; gap: var(--sp3); margin-bottom: var(--sp4) }
.mk-gantt-head b { font-size: 14px; font-weight: 500 }
.mk-gantt-head .legend { margin-left: auto; display: flex; gap: var(--sp3); font-family: var(--mono); font-size: 11px; color: var(--ink-faint) }
.mk-gantt-head .legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px }
.mk-gantt-head .legend i.step { background: var(--ink) }
.mk-gantt-head .legend i.wait { background: color-mix(in srgb, var(--amber) 30%, transparent); border: 1px solid var(--amber) }
.mk-grow { display: grid; grid-template-columns: minmax(0, 11rem) 1fr; gap: 12px; align-items: center; padding-block: 5px }
.mk-grow .lb { display: flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: 12px; color: var(--ink-muted); min-width: 0 }
.mk-grow .lb .ord { color: var(--ink-faint) }
.mk-track { position: relative; height: 26px }
.mk-bar {
  position: absolute; top: 3px; height: var(--mk-tag); border-radius: var(--r-sm);
  display: flex; align-items: center; padding-inline: 8px;
  font-family: var(--mono); font-size: 11px; white-space: nowrap;
  background: var(--ink); color: var(--bg);
}
.mk-bar.wait { background: color-mix(in srgb, var(--amber) 18%, transparent); box-shadow: inset 0 0 0 1px var(--amber); color: var(--ink) }

/* --------------------------------------------------------------------------
   Code, commands, install. All three share one shell.
   -------------------------------------------------------------------------- */
.mk-code { background: var(--s1); border: 1px solid var(--line); border-radius: var(--mk-radius); box-shadow: var(--mk-lift); overflow: hidden }
.mk-code-bar { display: flex; align-items: center; gap: var(--sp2); height: var(--mk-bar); padding: 0 14px; border-bottom: 1px solid var(--line); font-family: var(--mono); font-size: 12px; color: var(--ink-faint) }
.mk-code-body { position: relative; padding: 8px }
/* The copy button floats over the top-right of the block, so the block
   reserves that corner instead of letting the button land on a token. */
.mk-code pre {
  margin: 0; padding: 14px; overflow-x: auto;
  background: var(--s2); border: 1px solid var(--line); border-radius: var(--mk-r);
  font-family: var(--mono); font-size: 12px; line-height: 1.65; white-space: pre;
  color: var(--ink-muted); scrollbar-width: none;
}
.mk-code pre::-webkit-scrollbar { display: none }
/* The button floats over the top-right corner, so the FIRST line reserves that
   corner with a float and the rest of the block keeps the full measure. Padding
   the whole <pre> instead indented forty lines to clear one button. */
.mk-code pre::before {
  content: ""; float: right; width: 40px; height: var(--control-h-2xs);
}
/* Monochrome syntax. A four-hue highlighter is the fastest way to make a
   marketing page look like a tutorial blog. */
.mk-code .k { color: var(--ink); font-weight: 500 }
.mk-code .s { color: var(--ink-muted) }
.mk-code .f { color: var(--ink) }
.mk-copy {
  position: absolute; top: 16px; right: 16px;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--control-h-xs); height: var(--control-h-xs); padding: 0;
  appearance: none; border: 1px solid transparent; border-radius: var(--ctl-r);
  background: transparent; color: var(--ink-faint); cursor: pointer;
  transition: color var(--fast), background-color var(--fast), border-color var(--fast);
}
.mk-copy:hover, .mk-copy:focus-visible { color: var(--ink); background: var(--active-shade) }
.mk-copy:active { background: var(--active-shade-raised) }
.mk-copy svg { width: 15px; height: 15px }
.mk-copy.copied { color: var(--green) }
.mk-copy.copied svg { display: none }
.mk-copy.copied::after {
  content: ""; width: 6px; height: 10px;
  border: solid currentColor; border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg) translate(-1px, -1px);
}
/* A floating control needs its own surface so code cannot show through it.
   Copy controls inside command rows stay quiet because the row is the surface. */
:is(.mk-code-body, .mk-term, .pane-code, .product-code-view, .product-command, .product-code-lines) .mk-copy {
  width: var(--control-h-2xs); height: var(--control-h-2xs);
  border-color: var(--line); background: var(--s1);
}
:is(.mk-code-body, .mk-term, .pane-code, .product-code-view, .product-command, .product-code-lines) .mk-copy:hover,
:is(.mk-code-body, .mk-term, .pane-code, .product-code-view, .product-command, .product-code-lines) .mk-copy:focus-visible {
  border-color: var(--line-2); background: var(--s2); color: var(--ink);
}
.mk-copy.copied, .mk-copy.copied:hover, .mk-copy.copied:focus-visible { color: var(--green) }

/* MK-Command, the one-line copyable. An INSET surface, not a dark slab: a
   command block pinned to #0e0f13 is the same defect as a pinned terminal, and
   there is no dark command surface in the product to justify it. --s2 with a
   --line-2 ring reads as a well in both themes. */
.mk-cmd {
  display: flex; align-items: center; gap: 8px; min-height: var(--mk-ctl-lg); padding: 0 8px 0 14px;
  border-radius: var(--mk-r); background: var(--s2); min-width: 0; overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.mk-cmd code { flex: 1; min-width: 0; font-family: var(--mono); font-size: 12px; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.mk-cmd code .p { color: var(--ink-faint) }
.mk-cmd .mk-copy { position: static; flex: 0 0 auto }
.mk-cmd .mk-copy:focus-visible { outline-color: var(--ink-muted); outline-offset: -2px }

/* Compact product window. Runtime and the related-product cards use this same
   frame, command row and status anatomy at different container sizes. */
.mk-mini-window {
  display: flex; flex-direction: column; width: 100%; height: 100%; min-width: 0;
  overflow: hidden; border: 1px solid var(--line-2); border-radius: var(--r-xl);
  background: var(--s1); box-shadow: var(--mk-lift);
}
.mk-mini-body {
  display: flex; flex: 1 1 auto; min-height: 0; flex-direction: column;
  justify-content: flex-start; gap: var(--sp2); padding: var(--sp4); overflow: hidden;
}
.mk-mini-rows { display: flex; min-height: 0; flex-direction: column }
.mk-mini-row {
  display: grid; grid-template-columns: 7px minmax(0, 1fr) max-content;
  align-items: center; gap: var(--sp2); min-height: var(--control-h-xs);
  border-top: 1px solid var(--line); font-size: var(--t-meta);
}
.mk-mini-row:first-child { border-top: 0 }
.mk-mini-row i { width: 7px; height: 7px; border-radius: 50%; background: var(--green) }
.mk-mini-row b { min-width: 0; overflow: hidden; font-weight: 500; text-overflow: ellipsis; white-space: nowrap }
.mk-mini-row code { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); white-space: nowrap }

/* MK-Install, the client rail over a fixed-height terminal so switching a tab
   never reflows the page around it. */
.mk-install { width: 100%; max-width: 720px }
.mk-clients {
  position: relative; display: flex; flex-wrap: nowrap; gap: var(--sp1);
  padding-bottom: var(--sp3); overflow-x: auto; scrollbar-width: none;
  scroll-behavior: smooth; isolation: isolate;
}
.mk-clients::-webkit-scrollbar { display: none }
.client-glider {
  position: absolute; z-index: -1; top: 0; left: 0; height: var(--mk-ctl-lg);
  border-radius: var(--mk-r); background: var(--active-shade);
  transition: transform var(--base) var(--ease), width var(--base) var(--ease);
}
.mk-client {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
  height: var(--mk-ctl-lg); padding: 0 14px 0 8px; border-radius: var(--mk-r); cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--ink-muted);
  font-family: var(--font); font-size: 13px;
  transition: color var(--fast);
}
.mk-client .slot { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: var(--r-sm); background: transparent }
.mk-client .slot img, .mk-client .slot svg { width: 14px; height: 14px }
[data-theme="dark"] .mk-client .slot img { filter: invert(1) }
.mk-client[aria-selected="true"] { color: var(--ink) }
.mk-install .mk-term { height: 214px }
.mk-install .mk-term pre { white-space: pre; overflow-x: auto }
.mk-install [data-panes] { position: relative; height: 214px }
.mk-install [data-panes] > [data-pane] {
  position: absolute; inset: 0; opacity: 1; transform: translateX(0);
  transition: opacity var(--base) var(--ease), transform var(--base) var(--ease);
}
.mk-install [data-panes] > [data-pane][hidden] { display: none }
.mk-install [data-panes] > .pane-enter { opacity: 0; transform: translateX(10px) }
.mk-install [data-panes] > .pane-leave { opacity: 0; transform: translateX(-10px); pointer-events: none }
.mk-install .mk-term { position: relative }
.mk-install .mk-term > .mk-copy { top: var(--sp3); right: var(--sp3); z-index: 2 }
.mk-install .mk-term > pre { padding-top: calc(var(--sp5) + var(--sp4)); padding-right: calc(var(--control-h-2xs) + var(--sp5)) }

/* --------------------------------------------------------------------------
   MK-Rates, the published rate list. Type and hairlines only; the numeral
   carries no colour, because colour is state and a price is not a state.
   -------------------------------------------------------------------------- */
/* ONE GRID FOR THE WHOLE LIST, and the rows are subgrids of it.
   Every row used to be its own grid resolving `minmax(0,1.05fr) minmax(0,2fr)
   auto` on its own content, so the `auto` price track came out a different width
   per row and the two flexible tracks divided a different remainder. Measured at
   1440: the description column started at x=220.8, 226.5, 229.4, 238.1, 246.8 and
   255.5 down six rows, and the price column started at six different x too.
   Nothing was aligned with anything.

   The container owns the tracks; each row spans them with `subgrid`. max-content
   on the price column sizes it to the longest price in the LIST rather than the
   longest in the row. */
/* THE CONTAINER IS THE PARENT, NOT THE LIST. An element can never match its own
   container query, and the moment the tracks moved onto .mk-rates the queries
   below stopped applying to it: the 3-track grid with a max-content price column
   survived to 320px and pushed the pricing page 431px wider than the viewport.
   Declaring the container on the parent is the same pattern the dashboard's own
   tables use for exactly this reason. */
:where(div, section, article, figure):has(> .mk-rates) { container: mkrates / inline-size }
.mk-rates {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 2fr) max-content;
}
.mk-rates > * { grid-column: 1 / -1 }
.mk-rate {
  display: grid; grid-template-columns: subgrid;
  align-items: baseline; gap: var(--sp4);
  padding-block: var(--sp4); border-top: 1px solid var(--line-2);
}
.mk-rates > .mk-rate:last-child { border-bottom: 1px solid var(--line-2) }
.mk-rate .nm { font-family: var(--mono); font-size: 14px; color: var(--ink) }
/* 14px literal, not var(--t-small): this is the last place in the kit that
   still read a SITE step, and the site's steps now move. See the note on .mk. */
.mk-rate p { margin: 0; font-size: 14px; color: var(--ink-muted); line-height: 1.55 }
.mk-rate .price { font-family: var(--mono); font-size: 14px; text-align: right; white-space: nowrap; color: var(--ink-muted) }
/* Container, not viewport: this table lives at 760px inside a chapter and at
   full width on the pricing page, and only its own width can say which. */
@container mkrates (max-width: 640px) {
  .mk-rates { grid-template-columns: minmax(0, 1fr) max-content }
  .mk-rate { row-gap: var(--sp2) }
  .mk-rate p { grid-column: 1 / -1 }
}
/* Past here "credits, $0.004 / megapixel" cannot hold one line in the column it
   has, and a cut price is worse than a wrapped one. */
@container mkrates (max-width: 420px) {
  .mk-rates { grid-template-columns: minmax(0, 1fr) }
  .mk-rate .price { white-space: normal; text-align: left }
}

/* .mk-composer, .mk-chips and .mk-chip are gone. There is one composer in this
   kit now and it is .mk-chat-composer, inside .mk-chat: the site used to show a
   22px-radius capsule-buttoned front door beside an 8px-radius Studio, which is
   two products. Use .mk-chat, with .mk-chat-sugg for the starter row. There is
   no .two modifier any more: the starter row is one side-scrolling line. */

/* --------------------------------------------------------------------------
   MK-Rules, the governance table. A header row and one track per field: the
   product's rules surface is a table, and a three-field list reads as a
   settings screen instead.
   -------------------------------------------------------------------------- */
/* The card reads the width and .mk-rules-grid owns the tracks, for the reason
   spelled out on .mk-steps: a container query never matches its own container,
   so a track change declared on the container itself silently does nothing. It
   was doing nothing here: at a phone width the cell moves below applied and the
   track change did not, which left the limit in an 8px track with "200 calls"
   hanging off the right edge. */
.mk-rules {
  width: min(880px, 100%); container: mkrules / inline-size;
  background: var(--s1); border: 1px solid var(--line); border-radius: var(--r-xl); overflow: hidden;
}
.mk-rules-grid {
  --rules-cols: minmax(9rem, 22rem) minmax(var(--sp2), 1fr) max-content max-content max-content;
  --rules-gap: var(--sp4);
  display: grid; grid-template-columns: var(--rules-cols); column-gap: var(--rules-gap);
}
/* Head and rows are subgrids of the table, so one set of intrinsic tracks
   resolves across the whole thing. Two separate grids never line up. */
.mk-rule { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: center; min-height: var(--row-h); padding-inline: var(--sp5) }
.mk-rule + .mk-rule { border-top: 1px solid var(--line) }
.mk-rules .head { font-size: 12px; font-weight: 510; line-height: 1.35; color: var(--ink-faint) }
/* The header cells sit on the same tracks as the values, so they take the
   same alignment: a right-aligned numeral under a left-aligned label reads as
   two columns rather than one. */
.mk-rules .head > :nth-child(3), .mk-rules .head > :nth-child(4) { text-align: right }
.mk-rule .nm { display: flex; align-items: baseline; gap: 10px; min-width: 0 }
.mk-rule .nm b { font-size: 14px; font-weight: 500; color: var(--ink) }
.mk-rule .nm span { font-size: 12px; color: var(--ink-muted) }
.mk-rule .lim { font-family: var(--mono); font-size: 14px; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--ink) }
.mk-rule .per { font-family: var(--mono); font-size: 14px; text-align: right; white-space: nowrap; color: var(--ink-muted) }
/* Below the width where a name and its id fit on one line, the id drops under
   the name rather than wrapping the name. A rule called "Daily spend / cap" is
   a rule the reader has to reassemble. */
@container mkrules (max-width: 640px) {
  .mk-rules-grid { --rules-gap: var(--sp3) }
  .mk-rule { padding-inline: var(--sp4) }
  .mk-rule .nm { flex-direction: column; align-items: flex-start; gap: 2px }
}
@media (max-width: 720px) { .mk-rule { padding-inline: var(--sp4) } }
/* Below this the five tracks cannot hold their intrinsic widths, and the table
   was silently clipping its last column: a governance table that loses the
   Active/Paused column is showing the reader everything except the answer. The
   period folds into the limit and the state moves under the name, so every
   value stays on screen instead of behind an edge with no scroll rail. */
@container mkrules (max-width: 470px) {
  .mk-rules-grid { --rules-cols: minmax(0, 1fr) max-content }
  .mk-rule { row-gap: 4px; padding-block: var(--sp3) }
  .mk-rules .head { display: none }
  .mk-rule .per { grid-column: 1; text-align: left; font-size: 12px }
  .mk-rule .lim { grid-column: 2; grid-row: 1 }
  .mk-rule .mk-state { grid-column: 2; grid-row: 2; justify-self: end }
}

/* --------------------------------------------------------------------------
   Crop anchors. The artifacts are full size at every width; the container
   crops them, and the anchor decides which column survives the crop.
   -------------------------------------------------------------------------- */
/* Centring splits the negative free space in half, so an anchor set against a
   centred overflowing child only ever lands at half its value, on top of a
   centring shift it was never calibrated against. Once the artifact is wider
   than the plate, the left edge is the origin and the anchor is the whole
   offset. */
@media (max-width: 1040px) {
  /* A truncated command is a command the reader cannot run. Below the width
     where it fits on one line, it wraps instead of ending in an ellipsis. */
  .mk-cmd { height: auto; align-items: flex-start; padding: 11px 8px 11px 14px }
  .mk-cmd code { white-space: pre-wrap; overflow: visible; text-overflow: clip }
}
@media (max-width: 560px) {
  /* The PROPERTY, not the padding, so the stage and the window stay in step at
     every breakpoint. 16px each side left the stage one pixel short of the boot
     card at 375 and clipped its right border; 12px clears it with room. */
  .mk-plate { --plate-pad: var(--sp3) }
  /* Code is white-space: pre and will not reflow, so on a phone it scrolls. It
     scrolls VISIBLY: a hidden rail is content the reader cannot tell is there. */
  .mk-code pre { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent }
  .mk-code pre::-webkit-scrollbar { display: block; height: 6px }
  .mk-code pre::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 3px }
  .mk-receipt { font-size: 11.5px; padding: 16px }
  /* The sequence rows stack rather than crop: an 11rem label track leaves 99px
     of bar on a phone, which collapses the two short bars to nothing. The
     duration moves out of the bar and onto the row label, because a 23px bar
     cannot hold "0.8s" and padding it out would misreport the proportion. */
  .mk-gantt { padding: 16px }
  .mk-grow { grid-template-columns: minmax(0, 1fr); gap: 2px; padding-block: 8px }
  .mk-grow .lb::after { content: attr(data-dur); margin-left: auto; color: var(--ink-faint) }
  .mk-track { height: 22px }
  .mk-bar { font-size: 0; padding-inline: 0 }
}
/* A component that is wider than the phone gets a scroll rail of its own
   rather than squashing, and the page body never scrolls sideways. */
.mk-scroller::-webkit-scrollbar { display: none }


/* The navigation rail leaves at compact widths. Chat and projection remain the
   two real working panes, using the shell's native one-third / two-thirds split. */
@container mkstage (max-width: 1000px) {
  .mk-shell[data-studio-shell] > .pane-rail { display: none }
}
@container mkstage (max-width: 620px) {
  .studio-overview .body { grid-template-columns: minmax(0, 1fr); padding-block: var(--sp2) }
  .studio-overview .mk-legend { display: none }
  .studio-overview .head .right .mk-pill:last-child { display: none }
}

/* The right pane's ONE header band: three projection tabs left, the pane's
   controls right, 56px, no rule under it. */
.pane-tabs { height: var(--mk-head); padding: 0 16px; flex: 0 0 auto; background: var(--s1) }
.pane-tabs .acts { margin-left: auto; display: flex; align-items: center; gap: 4px }
/* The band must not scroll its own controls off: .mk-tabrow scrolls by default
   so a narrow column keeps the tabs whole, but inside the pane the column is
   never narrower than the tabs, and a scroller here clipped the pill. */
.pane-tabs { min-width: 0; overflow: hidden }

/* The Code projection. The pane's body is the file, at the product's own 12px
   mono, and it scrolls under the band with no rule between them. */
.pane-code { flex: 1 1 auto; min-height: 0; overflow: hidden; padding: 0 16px 16px }
.pane-code pre {
  margin: 0; font-family: var(--mono); font-size: 12px; line-height: 20px;
  color: var(--ink-muted); white-space: pre; overflow: hidden;
}
.pane-code .k { color: var(--ink); font-weight: 500 }
.pane-code .s { color: var(--ink-muted) }
.pane-code .f { color: var(--ink) }

/* The Steps projection fills the pane rather than sitting in it as a card: it IS
   the pane's body, so it drops the frame the standalone block carries. */
.pane-studio > .mk-steps { flex: 1 1 auto; min-height: 0; padding: 0; border: 0; border-radius: 0; box-shadow: none; background: var(--s1) }
.pane-studio > .mk-steps > .mk-steps-grid { border: 0; border-radius: 0 }

/* A component artifact in a chapter window. .mk-code, .mk-win and .mk-receipt are
   not crops of an app, they are components, but a row of five artifacts where
   three sit on a stage and two float is the inconsistency the owner called out.
   So they get the same stage and the same 16:10 window, and they fill it: the
   window is the frame, so the component drops its own and stretches. A component
   with too little content to fill 422px would leave a hole, which is what
   .mk-plate.fit exists for; these three have the lines. */
.mk-crop > :is(.mk-code, .mk-win, .mk-term) {
  width: 100%; height: 100%; border: 0; border-radius: 0; box-shadow: none;
  display: flex; flex-direction: column;
}
.mk-crop > .mk-code > .mk-code-body { flex: 1 1 auto; min-height: 0; overflow: hidden }
.mk-crop > .mk-term > pre { flex: 1 1 auto; min-height: 0; overflow: hidden; font-size: 13px; line-height: 20px; padding: 16px 20px }
.mk-crop > .mk-term .caret { color: var(--ink-faint); animation: mk-caret 1.1s steps(1, end) infinite }
@media (prefers-reduced-motion: reduce) { .mk-crop > .mk-term .caret { animation: none } }

/* The install rail inside a chapter window. Outside a window it is ordinary UI
   with its own frame; inside one, the window is the frame, so the rail fills it:
   tabs at the top, the terminal as the body, one hairline between them. */
.mk-crop > .mk-install { max-width: none; width: 100%; height: 100%; display: flex; flex-direction: column; background: var(--s1) }
.mk-crop > .mk-install .mk-clients {
  align-items: center; min-height: calc(var(--mk-ctl-lg) + var(--sp4));
  padding: var(--sp2) var(--sp3); border-bottom: 1px solid var(--line);
}
.mk-crop > .mk-install [data-panes] { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column }
.mk-crop > .mk-install [data-panes] > [data-pane] { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column }
.mk-crop > .mk-install [data-panes] > [data-pane][hidden] { display: none }
.mk-crop > .mk-install .mk-term { flex: 1 1 auto; height: auto; margin-top: 0; border: 0; border-radius: 0 }

/* The copy button floats over the code's first line; the line gives it room. */
.mk-code-body pre { padding-right: 56px }
/* The code inset fills its card: a grey block ending 90px above the card's
   bottom edge reads as a band of dead card. */
.mk-crop > .mk-code .mk-code-body { display: flex }
.mk-crop > .mk-code .mk-code-body pre { flex: 1 1 auto; min-height: 100% }
/* Inside a full app shell the terminal is the centre pane's body, so it runs
   to the pane's bottom inset like the app's own terminal slot. */
.mk-shell .pane-cli > .mk-term { flex: 1 1 auto; min-height: 0; margin: 0 16px 16px; display: flex; flex-direction: column }
.mk-shell .pane-cli > .mk-term pre { flex: 1 1 auto; min-height: 0; overflow: hidden }
/* Install commands wrap on a phone rather than sliding under the card edge. */
@media (max-width: 620px) {
  .mk-install .mk-term pre { white-space: pre-wrap; word-break: break-word }
}
/* --------------------------------------------------------------------------
   MK-Node v2. The plain name-and-kind card was a wireframe next to the app it
   quotes: the product's node carries the capability's glyph in a ringed well, a
   state dot, and the metered price on the card. So does this one now.
   -------------------------------------------------------------------------- */
.mk-node.v2 { flex-direction: row; align-items: center; gap: 10px; padding: 8px 12px; width: 250px }
.mk-node.v2 .fx { white-space: nowrap }
.mk-node.v2 .fx .facts { text-align: left; overflow: hidden; text-overflow: ellipsis }
.mk-node.v2 .well {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--line); color: var(--ink-muted);
}
.mk-node.v2 .well svg { width: 14px; height: 14px }
.mk-node.v2 .main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 }
.mk-node.v2 .row1 { display: flex; align-items: center; gap: 7px; min-width: 0 }
.mk-node.v2 .row1 .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.mk-node.v2 .mk-dot { flex: 0 0 auto }
.mk-node.v2 .mk-dot.idle { background: transparent; box-shadow: inset 0 0 0 1.5px var(--ink-faint) }
.mk-node.v2 .price { flex: 0 0 auto; font-family: var(--mono); font-size: 12px; color: var(--ink); font-variant-numeric: tabular-nums }
.mk-node.v2 .price:empty { display: none }
/* "no spend" and "no call" are notes, not amounts. */
.mk-node.v2 .price { color: var(--ink-muted) }
.mk-node.v2 .price:first-line { color: inherit }
/* The fork is drawn with rounded elbows now; the stroke setup is unchanged. */
.mk-fork path { stroke-linejoin: round }
