/* =========================================================
   Kimio Design System — design tokens + base
   ---------------------------------------------------------
   The single, justified GLOBAL stylesheet for the shared UI
   (per blazor.instructions.md, component styles stay isolated;
   design tokens, fonts and resets are the one allowed global
   sheet). Transcribed from the frozen design prototype's
   colors_and_type.css — see
   docs/design/ui/prototype/ and docs/design/ui/prototype/README.md.

   Shipped as a Razor Class Library static web asset, so both
   hosts load it from _content/Kimio.UI/css/kimio-design.css.
   ========================================================= */

/* ---------- Fonts (bundled, offline-safe) ----------
   Variable woff2 faces (Inter: weight axis; Fraunces: optical-size
   + weight axes) live alongside this file under ../fonts/. Licences:
   Inter-OFL.txt, Fraunces-OFL.txt (both SIL Open Font License). */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url('../fonts/InterVariable.woff2') format('woff2');
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url('../fonts/Fraunces.woff2') format('woff2');
}

:root {
  /* =============================================================
     1. CORE PALETTE — derived from the mascot
     ============================================================= */

  /* Brand */
  --kimio-orange-50:  #FFF3EC;
  --kimio-orange-100: #FFE0CC;
  --kimio-orange-200: #FFC096;
  --kimio-orange-300: #FF9A5E;
  --kimio-orange-400: #FA7733;
  --kimio-orange-500: #F35A1C;   /* primary */
  --kimio-orange-600: #D63D08;
  --kimio-orange-700: #A32E05;
  --kimio-orange-800: #6F2003;

  /* Roof Blue — the hat */
  --roof-blue-50:  #EFF6FF;
  --roof-blue-100: #D8E8FE;
  --roof-blue-200: #B2D2FD;
  --roof-blue-300: #82B6FB;
  --roof-blue-400: #4E9AF9;      /* secondary */
  --roof-blue-500: #2E7DE8;
  --roof-blue-600: #1F60BF;
  --roof-blue-700: #174689;

  /* Meadow — the grass */
  --meadow-50:  #EFF8F5;
  --meadow-100: #D6EEE6;
  --meadow-200: #ADDDCB;
  --meadow-300: #88CDB6;
  --meadow-400: #70BEAC;         /* tertiary / positive */
  --meadow-500: #4FA08D;
  --meadow-600: #3A7E6F;
  --meadow-700: #295A4F;

  /* Sun — the glasses */
  --sun-200: #FDEAB0;
  --sun-300: #FBD974;
  --sun-400: #F4C13A;
  --sun-500: #DDA419;            /* warning */
  /* Completes the rung the dark block already carries (--sun-700: #F4C13A). Needed because --sun-500 on
     the soft warning fill is ~2:1 — well under WCAG 1.4.3's 4.5:1 for small text.

     The VALUE is not chosen freely: ItemSection.razor.css already consumed this rung as
     `var(--sun-700, #8a6300)`, which on light fell through to that literal because the rung existed only
     on dark. Defining it therefore changes that surface too, so it is defined AS the literal that surface
     was already rendering — the item-type editor's Accessibility section is unchanged, and #8a6300 clears
     the contrast floor for the chip at ~5:1 anyway. Its sibling `var(--sun-100, …)` / `var(--sun-200, …)`
     fallbacks are the same trap, still armed: ChipContrast #1194. */
  --sun-700: #8a6300;

  /* Terracotta — critical / over-cap / under-insured states. */
  --terracotta-50:  #FAE9E4;
  --terracotta-400: #E66A4A;
  --terracotta-500: #D63D08;
  --terracotta-600: #C8421F;
  --terracotta-700: #9F2E0F;

  /* Cream surfaces */
  --cream-0:   #FFFFFF;
  --cream-50:  #FFFBF3;          /* default app bg */
  --cream-100: #FAF4E8;
  --cream-200: #F2EAD8;
  --cream-300: #E6DBC2;

  /* Indigo Ink — the pupil */
  --ink-900: #1A173C;            /* primary text */
  --ink-700: #34315A;
  --ink-500: #5E5B7C;
  --ink-400: #807DA0;
  --ink-300: #A6A4BE;
  --ink-200: #CFCEE0;
  --ink-100: #E7E6F0;
  --ink-50:  #F4F3F9;

  /* Indigo with alpha — overlays and hairlines on cream */
  --ink-04:  rgba(26, 23, 60, 0.04);
  --ink-08:  rgba(26, 23, 60, 0.08);
  --ink-12:  rgba(26, 23, 60, 0.12);
  --ink-24:  rgba(26, 23, 60, 0.24);
  --ink-40:  rgba(26, 23, 60, 0.40);
  --ink-60:  rgba(26, 23, 60, 0.60);

  /* Status (semantic) */
  --status-positive: var(--meadow-500);
  --status-warning:  var(--sun-500);
  --status-critical: #D24545;
  --status-info:     var(--roof-blue-500);

  /* =============================================================
     2. SEMANTIC COLOR TOKENS — use these in app code
     ============================================================= */
  --bg:              var(--cream-50);
  --bg-raised:       var(--cream-0);
  --bg-sunken:       var(--cream-100);
  --bg-hero:         linear-gradient(180deg, #E8F1FE 0%, var(--cream-50) 60%);
  --glass-bg:        rgba(255, 251, 243, 0.92);   /* frosted bars / tab bar */
  --scrim:           rgba(26, 23, 60, 0.32);       /* sheet & modal backdrop */

  --fg:              var(--ink-900);   /* body */
  --fg-muted:        var(--ink-500);   /* secondary text */
  --fg-faint:        var(--ink-400);   /* tertiary / captions */
  --fg-inverse:      var(--cream-50);

  --border:          var(--ink-12);
  --border-strong:   var(--ink-24);

  --accent:          var(--kimio-orange-500);
  --accent-hover:    var(--kimio-orange-600);
  --accent-soft:     var(--kimio-orange-50);
  --accent-fg:       #FFFFFF;

  /* Selection/highlight colour for active navigation, breadcrumbs, the primary + button, and the
     "What it is" section. Orange on the light theme; the dark theme (.is-dark) re-points both to
     roof-blue, which reads better on the deep base. --selected-soft is the matching tint surface. */
  --selected:        var(--accent);
  --selected-soft:   var(--accent-soft);

  /* The ONE "there is something new here" unread dot (domain-switcher invitation dot #1040, generalising the BUI18.2
     #448 Activity-menu dot): every surface that signals something new draws the same mark, so they read as
     one signal rather than several inventions (the surfaces are listed in ux-principles.md §5).
     Deliberately the brand accent (orange), NOT --selected, which re-points to roof-blue on the dark theme
     and would have made the same dot change colour between themes. --accent resolves in both themes
     (--kimio-orange-500 is overridden to a brighter orange under .is-dark), so no dark override is needed.
     --unread-dot-ring is the halo that lifts the dot off the glyph beneath it, so it must match the SURFACE
     the dot renders on — NOT the app background. The default is the raised surface (the phone drawer and any
     panel painting --bg-raised); a host on a different surface overrides the token on its own element and it
     inherits down to the dot (the widescreen rail sets --cream-100 in SideNav.razor.css). Getting this wrong
     is not subtle: an app-background halo drew a visibly dark ring on the dark theme's lighter drawer. */
  --unread-dot:      var(--accent);
  --unread-dot-ring: var(--bg-raised);

  --link:            var(--roof-blue-500);
  --link-hover:      var(--roof-blue-600);

  --positive:        var(--meadow-500);
  --positive-soft:   var(--meadow-50);
  --warning:         var(--sun-500);
  --warning-soft:    #FFF6DB;

  /* TEXT weights of the accent and warning hues, for small text sitting ON their own soft fill (the
     environment chips). The soft fills are deliberately pale, so the full-strength hue on top of one
     lands near 2-3:1 — under the 4.5:1 WCAG 1.4.3 requires below 18.66px bold. Same hue, legible
     weight: the colour language is unchanged and only the text darkens. --warning-ink needs no dark
     override because --sun-700 already has one; --accent-ink does, since --kimio-orange-700 does not. */
  --accent-ink:      var(--kimio-orange-700);
  --warning-ink:     var(--sun-700);
  --critical:        var(--status-critical);
  --critical-soft:   #FCEAEA;

  /* Danger / error messaging — inline validation text, the save-paused banner, error boundaries.
     --strong is the readable text colour (a deep red on the cream base); the rest track the critical
     scale. The dark theme (.is-dark) re-points --strong / --danger to a LIGHT red, because this deep
     red is unreadable on the dark indigo base. */
  --colour-danger:         var(--critical);
  --colour-danger-strong:  #8A1C1C;
  --colour-danger-soft:    var(--critical-soft);
  --colour-danger-surface: var(--critical-soft);

  /* =============================================================
     3. TYPOGRAPHY
     ============================================================= */
  --font-display: 'Fraunces', 'Times New Roman', Georgia, serif;
  --font-text:    'Inter', system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-mono:    ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace;

  /* Type scale (rem-based, root = 16px) */
  /* 10px: the smallest step — the nav ＋'s bare-noun caption (BottomNav / NavMenu, #834). Defined here rather
     than repeated as a 0.625rem literal in each nav bar's isolated CSS, so the value has one home. */
  --fs-10: 0.625rem;   --lh-10: 0.9375rem;
  --fs-12: 0.75rem;    --lh-12: 1.05rem;
  /* 13px: the dev panel's dense body size. It was referenced with a literal fallback long before it was
     defined, which the blazor learnings call out as a hazard — an undefined token silently resolves to its
     fallback, so the design system stops being the single source of the value. Defined here so it is one. */
  --fs-13: 0.8125rem;  --lh-13: 1.15rem;
  --fs-14: 0.875rem;   --lh-14: 1.25rem;
  --fs-16: 1rem;       --lh-16: 1.5rem;
  --fs-18: 1.125rem;   --lh-18: 1.625rem;
  --fs-20: 1.25rem;    --lh-20: 1.75rem;
  --fs-24: 1.5rem;     --lh-24: 2rem;
  --fs-32: 2rem;       --lh-32: 2.375rem;
  --fs-40: 2.5rem;     --lh-40: 2.875rem;
  --fs-56: 3.5rem;     --lh-56: 3.75rem;
  --fs-72: 4.5rem;     --lh-72: 4.75rem;

  /* Weights */
  --fw-regular: 400;
  --fw-medium:  500;
  --fw-semibold: 600;
  --fw-bold:    700;

  /* Tracking */
  --tracking-tight:  -0.02em;
  --tracking-normal: 0;
  --tracking-wide:   0.04em;
  --tracking-eyebrow: 0.08em;

  /* =============================================================
     4. SPACING — 4pt grid
     ============================================================= */
  --space-2:  2px;
  --space-4:  4px;
  --space-6:  6px;
  --space-8:  8px;
  --space-12: 12px;
  --space-16: 16px;
  --space-20: 20px;
  --space-24: 24px;
  --space-32: 32px;
  --space-40: 40px;
  --space-48: 48px;
  --space-64: 64px;
  --space-96: 96px;

  /* -------------------------------------------------------------
     SHELL BODY INSET — the padding AppShell's .app-shell__body
     contributes on every side to every routed page (see
     AppShell.razor.css). Named once so a page compensating for
     that ambient inset (subtracting it back out of its own target
     padding) reads this token instead of hard-coding --space-16 —
     changing the shell's inset then changes it everywhere, rather
     than silently breaking every page's hand-computed compensation
     (item-page mobile reflow #835 review).
     ------------------------------------------------------------- */
  --shell-body-inset: var(--space-16);

  /* -------------------------------------------------------------
     FIELD LABEL GAP — the space between a field's CAPTION and the
     value it labels (the Ink Hierarchy's Caption → Stated step,
     ux-principles.md §6). One number, named once, because a label
     and its value are the single most repeated pairing in the app
     and readers notice the INCONSISTENCY long before they notice
     the value: the item page's own fields sat at 0.3rem while the
     split accessibility/environment gutters sat at 0.2rem, which
     read as the split captions being crammed onto their values
     (#835 review). Any surface pairing a caption with its value
     reads this token rather than picking its own number.
     ------------------------------------------------------------- */
  --field-label-gap: var(--space-6);

  /* =============================================================
     5. RADII
     ============================================================= */
  --radius-xs:   4px;
  --radius-sm:   8px;
  --radius-md:  14px;   /* buttons, inputs, tiles */
  --radius-lg:  20px;   /* cards */
  --radius-xl:  28px;   /* hero cards, sheets */
  --radius-2xl: 36px;   /* modals */
  --radius-pill: 999px;

  /* -------------------------------------------------------------
     TAG PILL geometry — the ONE size every tag reads at, whatever
     kind it is: an item label (TagChip), a Smart Tag (SmartTagChip)
     and a party relationship (TagPill) are all the same
     shape and size, so a mixed list does not look ragged. Only the
     COLOUR and the glyph differ between them. Defined here rather
     than in each component's isolated stylesheet, which is what let
     the relationship pill drift smaller than the others (#685).
     ------------------------------------------------------------- */
  --tag-pill-padding: 0.3rem 0.6rem;
  --tag-pill-gap: 0.35rem;
  --tag-pill-font-size: 0.82rem;
  --tag-pill-font-weight: 600;
  /* The leading glyph's box. It must be at least as tall as the tallest glyph any pill carries (the
     relationship icon, 13px), because a glyph larger than its box would stretch that pill and reintroduce
     the very drift this token exists to prevent. The compact Smart chip narrows it locally. */
  --tag-pill-glyph: 13px;

  /* =============================================================
     6. SHADOWS — warm-tinted, never neutral gray
     ============================================================= */
  --shadow-1: 0 1px 2px rgba(26, 23, 60, .04),
              0 2px 8px rgba(243, 90, 28, .06);
  --shadow-2: 0 4px 12px rgba(26, 23, 60, .06),
              0 8px 24px rgba(243, 90, 28, .08);
  --shadow-3: 0 12px 32px rgba(26, 23, 60, .10),
              0 24px 64px rgba(243, 90, 28, .10);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, .6);
  --shadow-focus: 0 0 0 2px var(--cream-50),
                  0 0 0 4px var(--roof-blue-400);

  /* =============================================================
     7. MOTION
     ============================================================= */
  --ease-out:    cubic-bezier(0.20, 0.80, 0.20, 1);
  --ease-in-out: cubic-bezier(0.40, 0.00, 0.20, 1);
  --ease-spring: cubic-bezier(0.20, 1.40, 0.30, 1);

  --dur-micro:   120ms;
  --dur-fast:    200ms;
  --dur-base:    320ms;
  --dur-slow:    600ms;

  /* =============================================================
     8. LAYERS
     ============================================================= */
  --z-base:    1;
  --z-raised: 10;
  --z-sticky: 50;
  --z-overlay: 100;
  --z-modal:  200;
  --z-toast:  300;

  /* =============================================================
     9. SAFE AREAS — device insets (status bar / home indicator).
     Bars add these so content clears the system chrome. Falls back
     to 0 where the platform reports no inset.
     ============================================================= */
  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-right:  env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left:   env(safe-area-inset-left, 0px);

  /* =============================================================
     10. BREAKPOINTS
     A plain CSS custom property cannot be read inside an @media
     condition, so this token is DOCUMENTATION, not something the
     @media rules dereference. It has no var() reference anywhere,
     and cannot have one; a matching rule is kept in step by hand.

     It governs ONE question — "is this a phone?" — and only the
     media queries that reflow a layout for phone width should use
     it. A px literal is right for that: device width is physical.

     It does NOT govern a CONTENT-FIT query — "has this column got
     narrow enough that a two-word label wraps / two columns of text
     stop fitting?" That depends on the text, not the device, so
     those keep their own measured value and stay in `rem`, which in
     a media query resolves against the browser's INITIAL font size
     and therefore tracks the reader's own text-size preference.
     Pulling such a query onto this token silently moves the band it
     fires in and drops that scaling — see ItemPage.razor.css's #826
     paired-label reservation (40rem), DomainDetailsPage (36rem),
     StartupJourney (30rem) and HomeHero (640px), each of which says
     in place why it is not this value (#835 review).

     A C# constant standing for the same phone width must name this
     token in its doc comment, since it cannot read it either — see
     PartySelect's NarrowBreakpointPx.
     ============================================================= */
  --breakpoint-mobile: 480px;

  /* =============================================================
     11. SECTION-STACK RHYTHM
     The tighter padding/gap for a page that stacks section cards
     (an item's ItemSection cards, or the item-types catalogue rows) —
     shared so the item page and the item-types page cannot drift
     apart again (item-page mobile reflow #835).

     Named per-side so a SHELL-HOSTED page (one that renders inside
     AppShell's .app-shell__body, which already contributes --space-16
     on every side — the item page, the item-types page) can compute
     exactly the extra padding it still needs on top of the shell's,
     rather than hand-copying a derived pixel value that would
     silently go stale if either number ever changes. A MODAL (no
     ambient shell padding — ItemTypeEditOverlay's .ite__body) reads
     the full --section-stack-padding shorthand directly.
     ============================================================= */
  --section-stack-padding-top: 8px;
  --section-stack-padding-x: 16px;
  --section-stack-padding-bottom: 24px;
  --section-stack-padding:
    var(--section-stack-padding-top)
    var(--section-stack-padding-x)
    var(--section-stack-padding-bottom);
  --section-stack-gap: 12px;
  /* The card/row corner radius shared by ItemSection's card (used by both the item page and the
     item-types edit overlay) and the item-types catalogue row — these had drifted to two unrelated
     hardcoded values (16px vs 10px), so the item-type edit overlay's cards read visibly bulkier/rounder
     than the item-types catalogue list even after their padding/gap were unified (#835 review
     follow-up). */
  --section-stack-radius: 12px;

  /* =============================================================
     12. SPLIT-TILE HEIGHT
     Shared by SplitAccessibilityScale and SplitEnvironmentGrid's
     tile grid (both widths — the mobile transpose and the wide
     top/bottom layout) so accessibility and environment cannot
     drift to two different tile heights again (item-page mobile
     reflow #835 review follow-up: "make the accessibility height
     match the environment one").
     ============================================================= */
  --split-tile-height: 90px;
  --split-tile-height-mobile: 38px;
}

/* =============================================================
   SEMANTIC TYPOGRAPHY CLASSES
   Apply directly: <h1 class="t-display"> etc.
   ============================================================= */
.t-display {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-56);
  line-height: var(--lh-56);
  letter-spacing: var(--tracking-tight);
  color: var(--fg);
  font-variation-settings: "opsz" 96;
}
.t-h1 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-40);
  line-height: var(--lh-40);
  letter-spacing: var(--tracking-tight);
  color: var(--fg);
  font-variation-settings: "opsz" 72;
}
.t-h2 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-32);
  line-height: var(--lh-32);
  letter-spacing: var(--tracking-tight);
  color: var(--fg);
  font-variation-settings: "opsz" 48;
}
.t-h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-24);
  line-height: var(--lh-24);
  color: var(--fg);
  font-variation-settings: "opsz" 36;
}
.t-h4 {
  font-family: var(--font-text);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-18);
  line-height: var(--lh-18);
  color: var(--fg);
}
.t-body {
  font-family: var(--font-text);
  font-weight: var(--fw-regular);
  font-size: var(--fs-16);
  line-height: var(--lh-16);
  color: var(--fg);
}
.t-body-strong {
  font-family: var(--font-text);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-16);
  line-height: var(--lh-16);
  color: var(--fg);
}
.t-small {
  font-family: var(--font-text);
  font-weight: var(--fw-regular);
  font-size: var(--fs-14);
  line-height: var(--lh-14);
  color: var(--fg-muted);
}
.t-caption {
  font-family: var(--font-text);
  font-weight: var(--fw-medium);
  font-size: var(--fs-12);
  line-height: var(--lh-12);
  color: var(--fg-faint);
}
.t-eyebrow {
  font-family: var(--font-text);
  font-weight: var(--fw-semibold);
  font-size: 0.6875rem;        /* 11px */
  line-height: 1rem;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--fg-muted);
}
.t-link {
  color: var(--link);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.t-link:hover { border-bottom-color: var(--link); color: var(--link-hover); }

/* =============================================================
   TRUNCATION UTILITIES
   ============================================================= */
/* A single-line "where am I" string (a top-bar eyebrow, a breadcrumb-style path collapsed to one line, …)
   is most useful truncated at the START, not the end: the reader already knows roughly where a path
   begins, but the TAIL — what it actually leads to right now — is the part worth keeping on screen (item
   type/#835 review: "we should always be able to read the leaf... the continuation should be at the
   beginning instead of the end"). Flipping `direction` to rtl moves the browser's ellipsis to the box's
   start edge; `text-align: left` then keeps the (ordinary LTR) text itself reading normally, left-aligned,
   with its END — the leaf — now the part that survives. Apply directly alongside `white-space: nowrap` +
   `overflow: hidden` + `text-overflow: ellipsis` on the element carrying the text (those three stay with
   the caller, since they usually combine with caller-specific sizing/typography). A MULTI-segment path
   (several distinct clickable crumbs, not one string) needs the different, structural "pin the leaf,
   shrink everything before it" treatment instead — see ItemTypePicker.razor.css's `crumb-first` /
   `crumb-middle` / `crumb-seg.is-leaf` and TopBar.razor.css's `top-bar__crumb--leaf`, which follow the
   same principle without sharing this class.

   REQUIRED OF EVERY CALLER: wrap the text itself in a `<bdi>`. The rtl flip above is a LAYOUT trick and
   must not reach the text's own bidi resolution. In an rtl paragraph a NEUTRAL character at the end of the
   run — a full stop, a bracket, a hyphen, an ellipsis — has no following strong character, so per the
   Unicode bidirectional algorithm (N1/N2 then L2) it takes the paragraph's direction and is painted at the
   LEFT edge, with paired brackets additionally mirrored: "Dad's Shed (old)" renders as "(old) Dad's Shed".
   The strings this class carries are user-authored domain and place names, so that is reachable rather than
   theoretical — and since the eyebrow is the app's statement of WHERE YOU ARE, a name can be crafted to
   misread ("Loft (read-only)" → "(read-only) Loft"). `<bdi>` isolates the text as its own paragraph, so its
   trailing neutrals resolve against the text's own direction while the container's rtl still puts the
   ellipsis on the start edge. Deliberately NOT `direction: ltr` on the bdi: its default auto-detection also
   gets a genuinely right-to-left name right. Digits need no help — bidi rule W7 folds a European number
   after a strong LTR character, so "Unit 12" was never affected. */
.truncate-start {
  direction: rtl;
  text-align: left;
}

/* ---------- Base resets ---------- */
html, body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Use the variable fonts' real weights/optical sizes; never synthesise (faux) bold/italic, which
     renders rough. Fraunces (display) and Inter (text) both carry the full 100–900 weight axis. */
  font-synthesis: none;
  font-optical-sizing: auto;
}

/* ---------- Standard clickable-field hover ----------
   A subtle, theme-aligned hover shared by every bordered "input zone" — text fields and the reusable
   pickers. On hover the border firms up to the muted foreground with a 1px inset ring (reads as a slightly
   thicker border, no layout shift), never the loud accent colour. This lives in the global (unscoped)
   sheet so one rule reaches these controls across every component. Borderless title fields (e.g.
   .domain-details__name) are intentionally excluded — they have no border to firm up. */
.item-page__field input:not([type="checkbox"]):not([type="radio"]),
.item-page__field select,
.item-page__field textarea,
.currency-picker__trigger,
.icon-picker__trigger,
.item-type-picker__trigger,
.kimio-select__trigger,
.fault-table__trigger {
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.item-page__field input:not([type="checkbox"]):not([type="radio"]):hover,
.item-page__field select:hover,
.item-page__field textarea:hover,
.currency-picker__trigger:hover,
.icon-picker__trigger:hover,
.item-type-picker__trigger:hover,
.kimio-select__trigger:hover,
.fault-table__trigger:hover {
  border-color: var(--fg-muted);
  box-shadow: inset 0 0 0 1px var(--fg-muted);
}

/* =============================================================
   DARK THEME
   Applied via `.is-dark` on the document root (set by the theme
   service per the user's Light/Dark/System choice). Because every
   component reads from the same primitive + semantic tokens,
   redefining the primitives here flips the whole app. The indigo
   "ink" scale is inverted (text becomes light) and the warm cream
   surfaces become deep indigo, keeping the brand's warmth rather
   than a flat black. Brand hues are preserved; only their
   ultra-light tint surfaces are darkened so soft fills don't glare.
   ============================================================= */
.is-dark {
  color-scheme: dark;

  /* Cream surfaces → deep indigo, elevation reads lighter */
  --cream-0:   #232046;
  --cream-50:  #16142C;
  --cream-100: #1E1B3A;
  --cream-200: #2B2854;
  --cream-300: #393466;

  /* Indigo ink scale → inverted to light text on dark */
  --ink-900: #F3F1FB;
  --ink-700: #D5D2E8;
  --ink-500: #A6A2C4;
  --ink-400: #8884A8;
  --ink-300: #6E6A90;
  --ink-200: #4D496F;
  --ink-100: #393557;
  --ink-50:  #29264A;

  /* Ink alphas → light hairlines & overlays on dark surfaces */
  --ink-04:  rgba(255, 255, 255, 0.045);
  --ink-08:  rgba(255, 255, 255, 0.08);
  --ink-12:  rgba(255, 255, 255, 0.12);
  --ink-24:  rgba(255, 255, 255, 0.22);
  --ink-40:  rgba(255, 255, 255, 0.38);
  --ink-60:  rgba(255, 255, 255, 0.62);

  /* Ultra-light brand tints → low-alpha so soft fills sit on dark */
  --kimio-orange-50:  rgba(250, 119, 51, 0.16);
  --kimio-orange-100: rgba(250, 119, 51, 0.20);
  --kimio-orange-200: rgba(250, 119, 51, 0.32);
  --roof-blue-50:     rgba(78, 154, 249, 0.16);
  --roof-blue-100:    rgba(78, 154, 249, 0.22);
  --roof-blue-600:    #6BA6FA;
  --roof-blue-700:    #82B6FB;
  --meadow-50:        rgba(112, 190, 172, 0.16);
  --meadow-100:       rgba(112, 190, 172, 0.22);
  --meadow-300:       rgba(112, 190, 172, 0.42);
  --meadow-600:       #74D6B6;
  --meadow-700:       #7FE0C0;
  --sun-100:          rgba(244, 193, 58, 0.14);
  --sun-200:          rgba(244, 193, 58, 0.18);
  --sun-700:          #F4C13A;

  /* Terracotta — must brighten on dark or the "Condition & value" accent reads as muddy brick red.
     Matches the prototype's .is-dark block (colors_and_type.css). */
  --terracotta-50:    rgba(214, 61, 8, 0.17);
  --terracotta-600:   #F0805E;
  --terracotta-700:   #F0805E;

  /* Brand primaries — nudge brighter so they pop on the dark base */
  --kimio-orange-500: #FA7733;
  --kimio-orange-600: #FF9A5E;
  /* The chip's text weight must invert on dark: the light-mode ink (--kimio-orange-700, #A32E05) is a
     deep brown that disappears on the translucent orange fill. --warning-ink needs no twin here because
     it aliases --sun-700, which this block already overrides. */
  --accent-ink:       var(--kimio-orange-600);

  /* Selection/highlight reads as roof-blue on dark (active nav, breadcrumbs, + button, "What it is")
     rather than orange; the soft tint follows to a translucent roof-blue surface. */
  --selected: var(--roof-blue-400);
  --selected-soft: var(--roof-blue-50);

  /* Semantic tokens carrying hardcoded hex need explicit dark values */
  --bg-hero:       linear-gradient(180deg, #1F2A4A 0%, var(--cream-50) 62%);
  --glass-bg:      rgba(22, 20, 44, 0.86);
  --scrim:         rgba(7, 6, 18, 0.58);
  --warning-soft:  rgba(221, 164, 25, 0.18);
  --critical-soft: rgba(210, 69, 69, 0.20);

  /* Danger / error messaging must invert to a LIGHT red on the dark base — the light-mode deep red
     (#8A1C1C) is near-unreadable on deep indigo. --strong is the text; --danger the border/accent. The
     soft/surface tints already follow --critical-soft (overridden just above), so they need no override. */
  --colour-danger:        #F0716B;
  --colour-danger-strong: #FF9E9E;

  /* Links a touch brighter for legibility on dark */
  --link:        var(--roof-blue-300);
  --link-hover:  var(--roof-blue-200);

  /* Shadows → real depth needs black, not warm tint, on dark */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .40),
              0 2px 8px rgba(0, 0, 0, .30);
  --shadow-2: 0 4px 14px rgba(0, 0, 0, .45),
              0 10px 30px rgba(0, 0, 0, .35);
  --shadow-3: 0 16px 40px rgba(0, 0, 0, .55),
              0 28px 70px rgba(0, 0, 0, .45);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, .06);
}

/* =============================================================
   12. TAG PILL — the ONE shape every tag wears
   =============================================================
   An item label (TagChip), a ⚡ Smart Tag (SmartTagChip) and a party
   relationship (TagPill) must be the same size, padding and shape, so a
   mixed list never looks ragged. Only their COLOUR treatment and their
   leading glyph differ.

   This is a GLOBAL class, not a set of tokens, because tokens were not
   enough: each component still wrote its own rule around them, and they
   drifted on the properties nobody thought to tokenise — TagChip set no
   line-height at all (so its line-box was taller than the others at
   identical padding), the Smart chip added letter-spacing, only one set
   box-sizing. Scoped CSS cannot be shared between components, so the one
   shape lives here and each component adds only its colours.

   The leading glyph — a colour dot, a ⚡ bolt, or a relationship icon —
   occupies a FIXED box, so a pill's height does not depend on which of
   them it happens to carry. */
.k-tag-pill {
  display: inline-flex;
  align-items: center;
  box-sizing: border-box;
  gap: var(--tag-pill-gap);
  padding: var(--tag-pill-padding);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;   /* the colour is the component's; the WIDTH is shared */
  font-family: var(--font-text);
  font-size: var(--tag-pill-font-size);
  font-weight: var(--tag-pill-font-weight);
  line-height: 1;
  letter-spacing: 0;
  /* Names render exactly as typed (BUI14.7 #766) — never forced to upper case. */
  text-transform: none;
  text-decoration: none;
  white-space: nowrap;
  vertical-align: middle;
  max-width: 100%;
}

/* The leading glyph's box: fixed, so every pill is the same height whichever glyph it carries. */
.k-tag-pill__glyph {
  flex: 0 0 var(--tag-pill-glyph);
  width: var(--tag-pill-glyph);
  height: var(--tag-pill-glyph);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* The label itself: it, not the pill, is what may be truncated. */
.k-tag-pill__label {
  overflow: hidden;
  text-overflow: ellipsis;
}

