﻿/* ============================================================================
   Cordis Suite — Studio profile v2.0
   ONLY for Cordis Studio, the Modeler desktop application.

   Load order: tokens.css → cordis.css → cordis-studio.css.
   No other application may load this file. Studio's tighter scale, its dark
   default and its window chrome exist because a modelling workbench holds five
   panels at once — they are not a style another application may adopt.
   ========================================================================= */

:root {
  /* Chrome metrics. Studio has no density switch; these are the only heights. */
  --cordis-titlebar-h:  40px;
  --cordis-menubar-h:   26px;
  --cordis-statusbar-h: 26px;
  --cordis-rail-w:      54px;
  --cordis-tabstrip-h:  36px;
  --cordis-splitter-hit: 7px;

  /* The application's MINIMUM SIZE (Cordis IDE issue #771). Read by app.css's `.cordis-shell` and
     matched by the desktop head's own Window.Minimum* — a browser tab can only be given a CSS floor
     and then let the document scroll, an OS window has to be refused outright, and the two must agree
     or the refusal and the scrollbar disagree about what "too small" means. This is the size at which
     the chrome has finished giving way: the menu bar has folded to a hamburger, the command centre to
     its magnifier, both side panels are at their minimums, and the next pixel would come out of the
     editor. Tokens rather than literals in app.css so a host with lighter chrome can lower them. */
  --cordis-shell-min-w: 720px;
  --cordis-shell-min-h: 480px;

  /* The 2px step exists here and nowhere else in the suite: inside a 26px row
     there is no room for 4. */
  --cordis-space-0h: 2px;

  /* ---- The chrome's zoom floor (issue #24) ----------------------------------
     Page zoom scales CSS pixels and nothing else, so where a host owns the native
     title bar the OS caption buttons — drawn at a fixed DEVICE width, on top of our
     bar — stop matching any reserve expressed in CSS pixels. Zoomed to 67% the 140px
     below is ~94 device px against ~138 of buttons, and that band is a native
     non-client region: a click landing in it goes to the OS, so the host's rightmost
     chrome buttons stop being CLICKABLE before they stop being visible.

     Two runtime inputs and one ratio settle it. With R the display's rasterization
     scale, dpr = R x zoomFactor, so R/dpr is 1/zoom — the factor that takes the bar
     back to 100%. `comp` never shrinks the chrome (zoom out pins it), `shrink` never
     grows the caption reserve past the buttons' real width (zoom in trims it), and at
     zoom 1 both are exactly 1, which is every consumer that is not a native-chrome
     desktop head.

     Both inputs are DECLARED here, once, and OVERRIDDEN as inline styles on the root
     element — cordis-ui.js publishes --cordis-dpr (devicePixelRatio is browser-only),
     and the host publishes --cordis-chrome-raster because a page cannot tell zoom from
     display scale: it sees only their product. Inline on <html> beats a :root rule, so
     these values are the fallback rather than a competing declaration — and a host that
     publishes nothing gets 1, i.e. exactly the behaviour that shipped before. */
  --cordis-dpr: 1;
  --cordis-chrome-raster: 1;
  --cordis-chrome-comp:   max(1, calc(var(--cordis-chrome-raster) / var(--cordis-dpr)));
  --cordis-chrome-shrink: min(1, calc(var(--cordis-chrome-raster) / var(--cordis-dpr)));
}

/* Studio's own scale AND its own character — decision D9, decided 2026-08.
   Until D9 this block held six metrics and nothing else, so the only difference a
   consumer could see between the profiles was six pixel values: same shadows, same
   radii, same spacing rhythm. That is why Shell read as "Studio with taller
   controls". The three ladders below are the divergence. */
.cordis-studio {
  --cordis-control-h:  26px;
  --cordis-toolbar-control-h: 26px;
  --cordis-control-px: 8px;
  /* 12.5px, and it is a METRIC rather than a step on the type scale — see
     --cordis-fs-row in tokens.css for why that distinction is decision D7's answer. */
  --cordis-control-fs: 12.5px;
  --cordis-row-h:      26px;
  /* A tree row, not chrome — so it sits with the control metrics rather than in the
     :root block above, and tokens.css owns the Shell value (= the general row
     height). One declaration per selector; see TokenOwnershipTests. */
  --cordis-tree-row-h: 26px;
  --cordis-fs-row:     12.5px;
  /* 18px in a 26px row = 4px of ground above and below, which is the same proportion
     24px has in Shell's 44px row. The old literal 4px block padding put a ~23px pill
     in this row and it touched both borders. */
  --cordis-tag-h:      18px;
  --cordis-card-p:     12px;
  --cordis-nav-item-h: 26px;
  --cordis-section-gap: 12px;

  /* Radius · MEASURED off Cordis Studio, not reasoned about. This block said 3/4/4
     for a while on the theory that a workbench is squarer than a web page, and that
     theory was simply wrong: the IDE's own app.css declares --cordis-radius-sm: 6px
     and --cordis-radius: 8px, and across Cordis.IDE.UI there are 40 uses of the
     former against 4 of the latter. So Studio's small radius is 6px — exactly
     Shell's — and its large one is 8px.

     Which means sm is NOT redeclared here at all. Studio inherits Shell's 6px
     because that is the same number, and restating it would assert a difference
     that does not exist — the next person to widen Shell's small radius would
     leave Studio silently behind. Only md and lg move, from 10/16 down to a single
     8px: Studio has no modal-scale surface, so lg collapses onto md.

     The profiles are genuinely close here, and that is the finding. 3/4/4 made
     Studio look like a native Win32 dialog, which is the one thing it is not. */
  --cordis-radius-md: 8px;
  --cordis-radius-lg: 8px;

  /* Elevation · flat at rest. A workbench separates surfaces with 1px borders,
     not by floating them: sm is nulled outright, because every resting panel,
     card and toolbar in Studio used to carry a soft page-shadow it had no reason
     to. md and lg survive but tighter and darker — an overlay still has to read as
     being ABOVE what it covers, and that is true in any profile. */
  --cordis-shadow-sm: none;
  --cordis-shadow-md: 0 2px 6px rgba(0, 0, 0, 0.22);
  --cordis-shadow-lg: 0 6px 16px rgba(0, 0, 0, 0.30);

  /* Space · the middle of the rhythm compresses. 1 and 2 (4px, 8px) are shared,
     because they are the inside of a control and a 26px row has no smaller step to
     give. From 3 up, every rung comes down one: a workbench holds five panels at
     once, and a 32px gutter between two of them is a page's rhythm, not a
     workbench's. Studio previously overrode only --cordis-card-p, so the panels were
     tight and everything BETWEEN them was still spaced like a web page. */
  --cordis-space-3: 8px;
  --cordis-space-4: 12px;
  --cordis-space-5: 16px;
  --cordis-space-6: 24px;
  --cordis-space-7: 32px;
  --cordis-space-8: 48px;

  /* Caption tracking (issue #42) · the de-facto Studio caption is 11px, uppercase, .04em -- measured off the
     nineteen Studio sheets that each re-declared it -- where Shell's is .08em. The size, weight and uppercase
     are shared; only the tracking is the profile's, so it is the one caption token this block restates. Every
     DS caption (.cordis-caption, .cordis-prose h6, the menu group label) takes it from here, and a Studio sheet
     styling its own caption reads var(--cordis-ls-caption) instead of choosing a number. */
  --cordis-ls-caption: 0.04em;

  /* Decision D4 (2026-08): white on the brand-blue status bar in STUDIO, and only
     here. 3.1:1, accepted deliberately — Studio's bar is IDE window chrome, glanced
     at rather than read. Shell keeps tokens.css's dark blue-950 (5.3:1), because a
     Shell status bar carries information a user is expected to parse.

     On .cordis-studio rather than :root so there is exactly ONE declaration of this
     token per selector in the whole asset layer. Two files declaring it on :root
     would be the old app.css hazard in miniature: same property, same selector,
     order decides. */
  --cordis-statusbar-text: #FFFFFF;
}

/* D4 again, for dark — and it is a separate rule because the profile is a third axis crossing the two
   themes, not a value the theme layers may re-decide.

   The declaration above is on `.cordis-studio`, one class. Dark re-declares the same token: canonically
   on `[data-theme="dark"]`, which is `<html>` and therefore only ever INHERITED by the shell root, so
   Studio's own declaration already wins there. The IDE's mechanism is the other one, and it does not
   lose that way — the shell root carries `cordis-studio` and `cordis-dark` on the SAME element, and the
   compat shim mirrors dark onto `.cordis-shell.cordis-dark`: two classes to Studio's one, in the sheet
   that loads last. So the workbench's white silently became blue-950 on brand blue the moment the
   lights went out, with nothing failing — both values are legal and both resolve.

   Hence three classes on the class route, which is one more than the shim can bring, rather than the
   two-class `.cordis-studio.cordis-dark` used for --cordis-ghost-hover below: that token has no
   competing dark declaration, this one does. The attribute forms are declared too, so the value is
   right by either mechanism and stays right on the day the shim is deleted. */
[data-theme='dark'] .cordis-studio,
.cordis-studio[data-theme='dark'],
.cordis-shell.cordis-studio.cordis-dark { --cordis-statusbar-text: #FFFFFF; }

.cordis-studio .cordis-btn { height: 32px; padding: 0 14px; font-size: var(--cordis-fs-sm); }
.cordis-studio .cordis-btn--sm { height: 26px; padding: 0 10px; font-size: var(--cordis-fs-xs); }
.cordis-studio .cordis-btn--icon { width: 28px; height: 28px; padding: 0; }
/* A menu button (CordisButton Caret) keeps its caret's room here too: the square above is its floor. */
.cordis-studio .cordis-btn--icon.cordis-btn--menu { width: auto; min-width: 28px; padding: 0 3px 0 4px; }
.cordis-studio .cordis-btn:active { transform: none; }   /* no press scale in the workbench — see cordis.css */
.cordis-studio .cordis-input { height: 26px; padding: 4px 8px; font-size: var(--cordis-control-fs); }
.cordis-studio .cordis-label, .cordis-studio .cordis-field__label { font-size: var(--cordis-fs-caption); font-weight: var(--cordis-fw-semibold);
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--cordis-text-muted); }
/* The 2px step earns its keep here: 8px between a label and its 26px field is a web page's rhythm
   inside a workbench pane, and the SPECIFY editors stack a dozen of these rows. */
.cordis-studio .cordis-field { gap: var(--cordis-space-0h); }
.cordis-studio .cordis-check { width: 15px; height: 15px; flex-basis: 15px; }
.cordis-studio .cordis-check:checked::after { left: 4px; top: 1px; width: 4px; height: 8px; }
/* The switch scale, D10 family merge #2. These three used to be a rule set overriding
   `.cds-switch`'s geometry directly, which meant the COMPONENT — a different DOM with the same job
   — never saw them and shipped these Studio numbers in Shell as well. As tokens they reach both
   halves, and the geometry rules live once each in cordis.css. */
.cordis-studio {
  --cordis-switch-w:     24px;
  --cordis-switch-h:     14px;
  --cordis-switch-thumb: 10px;
}

/* A workbench glyph takes its size from the row it sits in. cordis.css sets .cordis-icon
   to a literal 20px with a baseline nudge, which is right for Shell markup that drops an
   icon straight into running text and wrong for a 26px panel row — and before D10 merged
   the two icon class names, Studio simply never saw those declarations. This hands them
   back. The named sizes (--sm / --lg) still work in both profiles: they are a deliberate
   size, not an inherited one. */
.cordis-studio .cordis-icon { font-size: inherit; vertical-align: baseline; }

/* Studio's spinner is not brand-coloured, and that is not a preference either — the IDE spins a
   glyph in currentColor everywhere it waits (`.cordis-spin` on CordisIcons.Loading: the panel tab
   strip, the deploy panel, the SCM history and the model checker), so a blue arc from
   `.cordis-spinner` would be the only blue spinner in the application and would read as a status
   rather than as "working". currentColor puts the ring on the same footing as the glyph: it follows
   whatever row or button it was dropped into. Shell keeps the accent arc, where a spinner is
   usually the only thing on a waiting card and has nothing to inherit from. */
.cordis-studio .cordis-spinner { border-top-color: currentColor; }

/* ---------- Studio parity ------------------------------------------------- */
/* Two retunings in cordis.css are right for Shell and are a regression in a workbench.
   Both are kept as PROFILE overrides rather than argued back into the canonical rules,
   because in both cases the Shell value is the better answer for a Shell surface. (A
   third one, the near-invisible dark border, was NOT handled here: that was a contrast
   defect rather than a profile difference, so tokens.css was lifted instead.) The Cordis
   IDE records all three in docs/dev/design-system-migration-deltas.md.

   The neutral chrome wash. Studio's surfaces are walls of icon buttons -- every panel
   head, the tab strip, the SPECIFY member toolbars -- and there a hover has to read as
   "this is a button", not as an accent state; --cordis-primary-soft turns a quiet toolbar
   into a light show. Shell keeps the blue tint, where a ghost button is one of two on a
   card and the tint is the affordance. Declared as a Studio token rather than read from the legacy
   shim's --cordis-hover so these rules outlive that file's deletion; and named --cordis-ghost-hover
   rather than --cordis-chrome-hover because that name is already taken, by the white wash the title
   bar's own controls use over brand blue -- a different surface and a different value in light. */
/* The title bar's chrome ink, declared by the Studio profile so CordisTitleBarAction does not depend on the
   legacy shim (the sheet a consumer is expected to stop linking). The title bar exists only in Studio and is
   dark in BOTH themes, so these are deliberately literal and do not step with the theme; the values are the
   shim's, which keeps declaring them for its own older readers until it is deleted. */
.cordis-studio {
    --cordis-chrome-fg: #CFCDC8;
    --cordis-chrome-active: #FFFFFF;
    --cordis-chrome-hover: rgba(255, 255, 255, 0.07);
}

.cordis-studio { --cordis-ghost-hover: rgba(17, 24, 39, 0.05); }
[data-theme='dark'] .cordis-studio,
.cordis-studio[data-theme='dark'],
.cordis-studio.cordis-dark { --cordis-ghost-hover: rgba(255, 255, 255, 0.07); }

/* A ghost or icon button in Studio is chrome: dim at rest, neutral when hovered.
   cordis.css paints it --cordis-primary-text on --cordis-primary-soft, which made every
   ghost button in the shell blue. A TONED button keeps its own states -- it is making a
   claim, not being chrome -- so all three are excluded rather than overridden back.

   The exclusion has to name all three (cordis-ide#843). It listed --danger alone, which was
   the whole set at the time; the moment --success and --warning existed, this selector was
   more specific than their hover rules and quietly repainted a green Run button the same
   neutral grey as every other icon in the bar -- on hover only, so it read as the colour
   being a rest-state decoration rather than as this rule winning.

   Since D16 cordis.css gives every icon button the muted glyph and a neutral hover itself, so the icon
   half of this rule only supplies Studio's VALUE of that wash (the lighter --cordis-ghost-hover). A
   PRESSED toggle (.is-active) is excluded: its wash is its state, and this would blink it off on hover. */
.cordis-studio .cordis-btn--ghost:not(.cordis-btn--danger, .cordis-btn--success, .cordis-btn--warning) { color: var(--cordis-text-muted); }
.cordis-studio .cordis-btn--ghost:not(.cordis-btn--danger, .cordis-btn--success, .cordis-btn--warning):hover:not(:disabled),
.cordis-studio .cordis-btn--icon:not(.cordis-btn--danger, .cordis-btn--success, .cordis-btn--warning, .is-active):hover:not(:disabled) {
  background: var(--cordis-ghost-hover); }

/* A field sits RECESSED into its panel, so its background is the rung BELOW
   --cordis-surface. Load-bearing on dark, where the panel and the canonical input
   background are the same #242932: the field lost its fill entirely and every SPECIFY
   name/value row read as plain text with a box around it. Only the background moves --
   --cordis-border-strong on the edge is an improvement in both profiles and stays.

   DARK ONLY, and the qualifier is the fix rather than a scoping tidy-up. The recess was
   written unqualified, but the collision it answers exists only on dark; on light the
   panel is --cordis-surface (#FFFFFF) and --cordis-bg is #F1F4F8, so the same declaration
   painted every text field the panel's own grey. That would be merely a taste call if the
   text field were the only control -- but it is not: .cordis-numeric and .cordis-select
   fill with --cordis-body-bg, which is white on light. So one SPECIFY row showed a white
   DEFAULT VALUE beside a grey UNIT, a white DIMENSION beside a grey one, and a text field
   read as disabled next to an identical enabled numeric one. Reported from a running app
   (2026-08, the AnalogInput property pane). On dark, --cordis-bg and --cordis-body-bg
   differ by design and the recess stays exactly as it was. */
.cordis-studio.cordis-dark .cordis-input,
.cordis-studio.cordis-dark .cordis-textarea { background: var(--cordis-bg); }

/* ---------- the focus indicator is INSET in Studio ------------------------- */

/* The universal ring in cordis.css is a box-shadow, which paints OUTSIDE the focused element's
   border and belongs to nothing else. On a Shell page that is correct and it is why the ring was
   made solid: there is space around a control, so a halo is the clearest indicator there is.

   In a workbench there is no space around a control, and a halo is wrong in three distinct ways --
   all three reported from a running app (2026-08):

   1. **It escapes.** A 26px tree row, a 28px tab, a toolbar band: the ring lands on the rows above
      and below, so the indicator points at three things at once.
   2. **It is clipped.** A tab strip, an activity rail and a diagram node are `overflow: hidden`
      containers by necessity, so the ring is not drawn around the control -- it is cut into a blue
      edge smear on whichever side is against the clip.
   3. **It appears when nobody asked for focus.** This is the one that generated the report. Chrome
      does not match `:focus-visible` for a POINTER click on a button, but the moment any key is
      pressed the focused element starts matching -- and a workbench is driven by shortcuts. So
      clicking a toolbar button and then pressing a shortcut lights that button up, minutes later,
      with no keyboard navigation anywhere in the story.

   So the ring is REPLACED, not removed (css/CLAUDE.md rule 8): a 2px accent outline with a NEGATIVE
   offset, drawn inside the control's own box. Keyboard focus stays as visible as it was and at the
   same contrast, it cannot escape a row or be clipped by a container, and it costs zero geometry. The
   menu bar already did exactly this per-control (`.cordis-menubar__button:focus-visible`), for the same
   reason and in the same band -- this generalises that answer to the profile instead of waiting for
   each dense control to rediscover it.

   The two-selector shape mirrors the heading rule in cordis.css: one blanket rule, then the narrow
   opt-outs where the control ALREADY has a focus presentation of its own and a second one only
   thickens it. A text field switches its border to the accent colour on `:focus`; an inset outline
   inside a 26px field sits on top of that border and reads as a 3px edge.

   The opt-out list is the FIELD FAMILY, and membership follows from behaviour, not from which
   component happens to render the control. `.cordis-numeric` was missing from it for no reason
   anyone recorded: it moves its border to the accent on `:focus` exactly as `.cordis-input` does,
   so it was drawing the very 3px edge described above, on the DEFAULT VALUE and LOWER/UPPER LIMIT
   boxes of every SPECIFY row -- beside a text field that opted out and therefore did not. Adding
   a fourth field-shaped control here is not a licence to grow this list: the test is that the
   control replaces the ring with a focus presentation of its own, and a control that merely looks
   like a field still needs the ring. */
.cordis-studio :focus-visible {
  box-shadow: none;
  outline: 2px solid var(--cordis-accent);
  outline-offset: -2px;
}
/* Case 3 above is answered here, not by the inset (#52): while the user's last move was a POINTER press,
   cordis-ui.js's trackInputModality has data-cordis-modality="pointer" on <html> and the ring stays off.
   Tab or an arrow key turns it back on; a shortcut does not. Without the attribute the ring shows. */
[data-cordis-modality="pointer"].cordis-studio :focus-visible,
[data-cordis-modality="pointer"] .cordis-studio :focus-visible { outline: none; }
.cordis-studio .cordis-input:focus-visible,
.cordis-studio .cordis-textarea:focus-visible,
.cordis-studio .cordis-numeric:focus-visible,
.cordis-studio .cordis-select:focus-visible { outline: none; }

/* A COMPOSITE control opts out at the other end, and cannot be listed above. The element that holds
   focus inside .cordis-filter / .cordis-copyfield / .cordis-richtext is a bare <input> or a
   contenteditable div carrying none of those classes, while the ring belongs to the wrapper the user
   perceives as the control (:focus-within, in the Blazor library). So each of those suppresses BOTH
   ring properties on its own inner element -- box-shadow for Shell, outline for this profile. A
   composite control that suppresses only the shadow shows this profile's inset rectangle drawn around
   its inner box inside the wrapper's ring: the doubled highlight reported on Studio's explorer filter
   field, 2026-08. `CompositeFocusRingTests` fails the build for the next one that forgets. */

/* ---------- window chrome ------------------------------------------------- */

/* THE CHROME THAT USED TO BE HERE IS GONE (decision D10, 2026-08).
   Title bar, activity bar, status bar, tab strip, splitter, panel head and tree each had a short
   block in this file AND a full implementation in the Blazor component that renders it — two
   descriptions of one piece of chrome, agreeing only because both read the tokens.

   Which one to keep is not symmetric here, and it is the opposite of the answer for a button.
   `.cordis-btn` has two legitimate authors: a plain-HTML consumer writing the class by hand, and
   CordisButton. Studio's window chrome has exactly ONE consumer — Cordis Studio, which is Blazor —
   so a hand-written title bar is not a use case anybody has. The blocks here were also the thinner
   half: 12 lines of title bar against CordisTitleBar.razor.css's 70, 20 of tree against
   CordisTreeNode.razor.css's 121. Nothing in this repository, the showcase included, wrote the
   markup they styled.

   So the components own their chrome and this file keeps only what is genuinely profile-wide: the
   scale, the chrome METRICS above (which the components read as tokens), the menu bar (see the one
   exception below) and the two Studio-only text treatments at the end. Adding a chrome class back here
   means Studio has stopped being the only consumer of it — check that before you do. */

/* THE MENU BAR STAYS HERE, and it is the ONE exception to the rule the block above states -- because it
   is the one piece of Studio chrome with a second author. CordisMenuBar became a component in this
   library in Cordis IDE issue #588, so by that rule these rules should have followed it into
   CordisMenuBar.razor.css; reference/index.html hand-writes `.cordis-menubar` + `__item` in its Studio
   chrome demo, which is exactly the "nothing writes this markup" test failing, so deleting them here
   would ship the reference page's menu bar unstyled.

   The two do not collide. A standalone bar (the demo) is a full-height band with its own surface and a
   rule under it, which is what this block describes; the component's bar sits INSIDE the brand-blue
   title bar and is sized by its buttons, so its scoped sheet re-declares all four of those properties
   for itself -- deliberately and with a comment, since it is a 0-2-0 selector overriding a 0-1-0 one and
   that is not obvious from either file alone. If the demo ever goes, delete this block and the override
   with it.

   `.cordis-menubar__item` is a DIFFERENT story from the bar itself and these rules ARE live for the
   component: CordisMenuFlyout renders `{Block}__item` beside its own `cordis-menu__item`, and the bar
   passes `Block="cordis-menubar"`, so every dropdown row carries this class. That is deliberate -- the
   host-prefixed alias is what keeps existing selectors (and the IDE's e2e specs) resolving -- but it means
   the padding/colour/cursor here WIN over cordis.css's `.cordis-menu__item`, being one class each and
   later in the load order. Leave them alone unless you mean to restyle every menu-bar row: this is the
   only place they are set, and the component's own sheet does not re-declare them. The bar's top-level
   BUTTONS are `__button` and are styled in the component. */
.cordis-menubar { display: flex; align-items: center; gap: 2px;
  height: var(--cordis-menubar-h); padding: 0 6px;
  background: var(--cordis-surface); border-bottom: 1px solid var(--cordis-border); user-select: none; }
.cordis-menubar__item { padding: 4px 9px; border-radius: var(--cordis-radius-sm);
  font-size: var(--cordis-fs-sm); color: var(--cordis-text); cursor: default; }
.cordis-menubar__item:hover, .cordis-menubar__item.is-open { background: var(--cordis-surface-raised); }

/* ---------- diagnostics --------------------------------------------------- */

/* 10px is below the type scale on purpose: the count has to fit inside a 14px
   chip that sits on a 26px tree row. It is a fit constraint, not a text size. */
.cordis-diag { display: inline-flex; align-items: center; height: 14px; padding: 0 4px;
  border-radius: 4px; font-size: 10px; font-weight: 700; line-height: 1; }
.cordis-diag--error { background: var(--cordis-danger-soft); color: var(--cordis-danger-text); }
.cordis-diag--warn  { background: var(--cordis-warning-soft); color: var(--cordis-warning-text); }
.cordis-diag--dot   { width: 7px; height: 7px; padding: 0; border-radius: var(--cordis-radius-pill); }

/* ---------- code ---------------------------------------------------------- */
/* The one place Studio is allowed its own family: a monospace for code is a
   working tool, not a brand choice. Everything around the code uses the suite face. */

.cordis-code { font-family: 'Cascadia Code', var(--cordis-font-mono); font-size: var(--cordis-fs-sm);
  line-height: 1.5; color: var(--cordis-text); background: var(--cordis-bg); }
.cordis-code .tok-keyword  { color: var(--cordis-blue-500); }
.cordis-code .tok-call     { color: var(--cordis-success); }
.cordis-code .tok-type     { color: var(--cordis-type-violet); }
.cordis-code .tok-true     { color: var(--cordis-success); }
.cordis-code .tok-false    { color: var(--cordis-danger); }
.cordis-code .tok-number,
.cordis-code .tok-string   { color: var(--cordis-warning); }
.cordis-code .tok-variable,
.cordis-code .tok-comment  { color: var(--cordis-text-muted); }

/* Every hue steps one lighter on dark; a light-theme red or violet used as
   text on a dark surface fails the contrast rule. */
[data-theme='dark'] .cordis-code .tok-type { color: var(--cordis-type-violet-dark); }

/* ---------- not in Studio ------------------------------------------------- */
/* Studio has no sign-in, no density switch and no phone layout. If you find
   yourself needing one of these here, you are building a Shell application. */

.cordis-studio .cordis-tabbar { display: none; }

/* ...and Studio has no TOUCH floor either, which is the same statement about the same thing and was
   the one half nobody wrote down. css/cordis.css lifts the control family to a 44px minimum below
   640px, for a Shell form under a thumb. A workbench narrowed to 640px is not a phone -- it is a
   workbench someone has made narrow, still driven by a mouse, and its whole profile exists to put a
   control at 26px. Left unopted-out, the floor beat `height: var(--cordis-control-h)` (a min-height
   always does) and a SPECIFY row measured 44px on its text input against 26px on the numeric field
   beside it, live, 2026-08. Restoring the control height rather than zeroing the floor keeps the
   declaration meaningful if the family's own height ever moves. */
@media (max-width: 640px) {
  .cordis-studio .cordis-btn, .cordis-studio .cordis-input, .cordis-studio .cordis-textarea,
  .cordis-studio .cordis-numeric, .cordis-studio .cordis-select__trigger,
  .cordis-studio .cordis-copyfield, .cordis-studio .cordis-filter { min-height: var(--cordis-control-h); }
}
