/* ============================================================
   RIPROKA - DESIGN TOKENS
   ------------------------------------------------------------
   Extracted from the TechBillingApp (C:\SPRFApp\TechBillingApp),
   which is the visual template for RIPROKA.

   Aesthetic: INDUSTRIAL JOB TICKET. Warm paper, ink, safety
   orange. Condensed display type, mono numbers, cut-corner
   cards, stamp-style status chips.

   THE RULE: no component stylesheet may contain a raw colour,
   size, radius or shadow. Everything references a token here.
   That is what makes a theme change one file instead of a
   find-and-replace across the app.

   There is no Bootstrap in RIPROKA and there never will be.

   ------------------------------------------------------------
   HOW THE THEME BLOCKS ARE ORGANISED, AND WHY

   Four blocks, in this order, and the order is load-bearing:

     1. the :root block            the light theme + everything
                                   that does not flip
     2. the light-island block     the flipping half of block 1,
                                   restated on a bare data-theme
                                   attribute so a LIGHT ISLAND can
                                   sit inside a dark page
     3. the prefers-color-scheme
        media query                system dark, opt-out-able
     4. the explicit dark block    the dark toggle, and a DARK
                                   ISLAND inside a light page

   ⚠️ DO NOT WRITE A BLOCK'S FULL SELECTOR INTO A COMMENT ABOVE IT.
   ThemeContrastTests and DesignSystemTests find each block with a
   plain IndexOf of its selector text and then take the NEXT brace.
   A selector quoted in a comment is found first, the readers latch
   onto the wrong block, and every colour gate silently starts
   measuring the light theme twice. That is exactly what happened
   the first time this header was written.

   Blocks 2 and 4 are what let the control-kit gallery show every
   component in both themes on one screen: an element carrying
   data-theme wins over the inherited :root values for its own
   subtree, because custom properties inherit and the nearer
   declaration is the one that applies.

   Block 2 duplicates block 1's flipping tokens. That duplication
   is deliberate and it is GATED - DesignSystemTests asserts the
   two agree token for token, so a light-theme edit that forgets
   the island block fails the build instead of shipping a panel
   that is half dark.
   ============================================================ */

:root {
    /*
       -- THE NATIVE HALF OF THE THEME ------------------------
       color-scheme is the ONLY way to reach the parts of a control the browser draws
       itself: a date input's calendar glyph, a select's own dropdown list, a
       scrollbar, an autofill background. None of them read a custom property, so
       without this a date field in the dark theme paints a near-black icon on a
       near-black field and simply disappears - the same class of failure as the app
       bar, one layer further down where no CSS of ours can reach.

       It is declared in every theme block below for the same reason the colours are.
    */
    color-scheme: light;

    /* -- COLOUR - surfaces ---------------------------------- */
    --rk-paper:        #f3efe6;   /* page background, "warm paper" */
    --rk-card:         #fffdf7;   /* raised surface */
    /* The width of one RkFileShot tile. A photograph on a record is a fixed 4:3
       frame so a landscape camera shot and a portrait data plate sit in one row
       without one being three times the height of the other. .rk-shot--compact
       overrides this on itself. */
    --rk-shot-w: 150px;
    --rk-white:        #ffffff;   /* inputs, text on accent */

    /*
       --rk-field IS THE INPUT SURFACE, AND IT EXISTS BECAUSE
       --rk-white IS A TRAP. In the dark theme --rk-white resolves
       to #e9e4d8, the same value as --rk-ink, so an input painted
       `background: var(--rk-white); color: var(--rk-ink)` - which
       is exactly what the source app does - is INVISIBLE. This is
       the same failure CLAUDE.md records for the app bar, one
       control along. Every text-entry surface uses --rk-field.
    */
    --rk-field:        #ffffff;

    /* -- COLOUR - ink / text -------------------------------- */
    --rk-ink:          #16232d;   /* primary text AND dark chrome */
    --rk-ink-deep:     #000000;   /* dark-button underline */
    --rk-ink-soft:     #3c4c58;   /* secondary text */
    --rk-steel:        #4e6e81;   /* tertiary text, blueprint blue */

    /*
       DELIBERATE DEVIATION FROM THE SOURCE APP, AND THE ONLY ONE IN THIS BLOCK.
       Its placeholder is #b3ac9b, which measures 2.26:1 on a white field - below
       even the 3:1 floor, on text that tells a field technician what to type,
       outdoors. #8f8878 is the same warm grey two steps darker and measures
       3.52:1. Gated in DesignSystemTests, both themes.
    */
    --rk-placeholder:  #8f8878;   /* input placeholder */

    /* -- COLOUR - lines ------------------------------------- */
    --rk-line:         #d9d2c0;   /* soft / dashed divider */
    --rk-line-hard:    #b9b09a;   /* card + input border */

    /* -- COLOUR - accent (safety orange) -------------------- */
    --rk-accent:       #e8590c;   /* primary action */
    --rk-accent-deep:  #b23e00;   /* pressed edge / stamp ink */
    --rk-accent-soft:  #fdeee3;   /* active row tint */

    /* -- COLOUR - status ------------------------------------ */
    --rk-ok:           #2b8a3e;
    --rk-ok-soft:      #edf4e7;
    --rk-danger:       #c92a2a;
    --rk-danger-soft:  #fdecec;
    --rk-danger-deep:  #7d1a1a;
    --rk-warn:         #e8590c;   /* the source had no warning colour; orange doubles */
    --rk-warn-soft:    #fdeee3;

    /*
       -- COLOUR - THE TWO INK DIRECTIONS ON A STATUS ---------

       A status colour is used two ways and they need DIFFERENT
       inks. Getting this wrong is how the dark theme ships
       unreadable, and it already measured unreadable once:
       ThemeContrastTests records --rk-white on --rk-accent at
       2.05:1 in dark, against a 3:1 floor for a button label.

       --rk-on-fill   text sitting ON a saturated fill
                      (a primary button, a filled chip, a count
                      badge). White in light, near-black in dark,
                      because the dark theme lightens BOTH ends
                      of the white-on-orange pair until they meet.

       --rk-*-ink     the status used AS text, on paper, on a
                      card, or on its own soft tint (a stamp, a
                      notice, a filled madlib blank). Goes darker
                      in light and LIGHTER in dark - the opposite
                      direction to the fill ink, which is the
                      whole reason these are separate tokens.

       Measured, both themes, in DesignSystemTests. Do not paint
       text on a status fill with anything but --rk-on-fill, and
       do not paint status-coloured text with the raw status
       token - use the -ink.
    */
    --rk-on-fill:      #ffffff;
    --rk-accent-ink:   #b23e00;
    --rk-ok-ink:       #1e6b2c;
    --rk-danger-ink:   #7d1a1a;
    --rk-warn-ink:     #b23e00;

    /* -- COLOUR - disabled ---------------------------------- */
    --rk-disabled:      #a9a293;
    --rk-disabled-deep: #8d8677;
    --rk-disabled-text: #98917f;

    /*
       -- COLOUR - PERMANENT CHROME ---------------------------
       The app bar and other "always dark" chrome MUST use this pair, never
       `background: var(--rk-ink)` + `color: var(--rk-white)`.

       Why: in the dark theme --rk-ink and --rk-white both resolve to #e9e4d8,
       so that idiom renders light-on-light at a 1:1 contrast ratio and the
       wordmark disappears entirely. Caught by rendering the real app, not by
       reading the CSS. These two tokens do NOT flip with the theme, which is
       correct - the chrome is dark on purpose in both themes.
    */
    --rk-chrome-bg:   #16232d;
    --rk-chrome-ink:  #ffffff;
    --rk-chrome-mute: #8d9aa3;

    /* -- COLOUR - dark viewer chrome (the one dark surface) -- */
    --rk-dv-0:    #0b1319;
    --rk-dv-1:    #0d1419;
    --rk-dv-2:    #16202a;
    --rk-dv-3:    #1a252c;
    --rk-dv-4:    #3a5464;
    --rk-dv-mute: #8d9aa3;

    /*
       -- COLOUR - THE DATA RAMP, AND IT IS ANCHORS RATHER THAN A PALETTE ---

       A legend needs ONE COLOUR PER DISTINCT VALUE, and nobody knows how many
       values there are until the rows come back. Charlie's runs 963 zones. So
       the ramp cannot be a list of hexes in this file - it is GENERATED, in
       C#, by RkDataPalette, and what lives here are the numeric anchors that
       generator reads its shape from. Colour still has exactly one declaration
       site; it is just that this one declares a ramp instead of a swatch.

       🛑 NOTHING PAINTS THESE. They are read as NUMBERS. The five --rk-data-l*
       are neutral greys purely so their HSL lightness reads straight off the
       channel; the five --rk-data-c* are one reference hue at L=0.5 purely so
       their HSL saturation reads off (max - min). A red here is not a red the
       product draws - it is the number 0.76 wearing a hex so it can live in
       the token file with everything else.

       ⚠️ AND THEY DO NOT FLIP WITH THE THEME, deliberately, exactly like
       --rk-chrome-*. A zone's colour is an identity a dispatcher learns; if it
       moved between light and dark, two people looking at the same board would
       be describing different maps. Legibility is handled instead by
       --rk-data-on-light / --rk-data-on-dark, which a luminance test picks
       between per swatch.

       ⚠️ "data" RATHER THAN "map" IS DELIBERATE, ON TWO COUNTS. The ramp is not
       map-specific - a chart or a board colouring by a category wants the same
       one - and --rk-map-* is already taken by RkMap's basemap chrome, which is
       a different thing entirely. Two concepts under one prefix is how somebody
       later "tidies" one into the other.

       MapColorScaleTests.EveryPaletteAnchorStillMatchesItsToken asserts the C#
       constants still equal these values, so editing one here and not there is
       a red build rather than a drift.
    */
    --rk-data-none:     #8a8279;   /* the (none) swatch - reads on paper AND on ink */
    --rk-data-on-light: #1b1b1b;   /* label sitting on a light generated swatch */
    --rk-data-on-dark:  #ffffff;   /* label sitting on a dark generated swatch */

    /* the lightness ladder - cycles every step, because equal hue steps are
       not equal perceptual steps and lightness is what rescues the blues */
    --rk-data-l1:       #757575;
    --rk-data-l2:       #a3a3a3;
    --rk-data-l3:       #575757;
    --rk-data-l4:       #8f8f8f;
    --rk-data-l5:       #424242;

    /* the chroma ladder - cycles every five steps */
    --rk-data-c1:       #c93636;
    --rk-data-c2:       #b24d4d;
    --rk-data-c3:       #e01f1f;
    --rk-data-c4:       #a65959;
    --rk-data-c5:       #f00f0f;

    /* -- COLOUR - channels, so rgba() never drifts from the hex -- */
    --rk-ink-rgb:    22, 35, 45;
    --rk-paper-rgb:  243, 239, 230;
    --rk-card-rgb:   255, 253, 247;
    --rk-steel-rgb:  78, 110, 129;
    --rk-danger-rgb: 201, 42, 42;

    /* -- COLOUR - derived alphas ---------------------------- */
    --rk-scrim:       rgba(var(--rk-ink-rgb), 0.45);
    --rk-press-ghost: rgba(var(--rk-ink-rgb), 0.06);
    --rk-grid-line:   rgba(var(--rk-steel-rgb), 0.07);
    --rk-err-wash:    rgba(var(--rk-danger-rgb), 0.06);

    /*
       Desktop needs what a phone-only app never had: a hover
       treatment and a zebra stripe. Both are derived alphas so
       they tint whatever surface they land on and never need a
       second value per theme.
    */
    --rk-hover-ghost: rgba(var(--rk-ink-rgb), 0.04);
    --rk-zebra:       rgba(var(--rk-steel-rgb), 0.05);
    --rk-skeleton:    rgba(var(--rk-steel-rgb), 0.18);
    --rk-skeleton-hi: rgba(var(--rk-steel-rgb), 0.06);

    /* -- TYPE - families ------------------------------------ */
    --rk-font-body:    'Barlow', system-ui, sans-serif;
    --rk-font-display: 'Barlow Condensed', 'Arial Narrow', sans-serif;
    --rk-font-mono:    'IBM Plex Mono', Consolas, monospace;

    /* -- TYPE - scale --------------------------------------- */
    --rk-fs-3xs:   9px;
    --rk-fs-2xs:  10px;
    --rk-fs-xs:   11px;   /* stamps, micro-labels */
    --rk-fs-sm:   12px;   /* small print */
    --rk-fs-md:   13px;   /* densest common size */
    --rk-fs-lg:   14px;   /* secondary body */
    --rk-fs-xl:   15px;   /* labels, dense body */
    --rk-fs-base: 16px;   /* html/body base */
    --rk-fs-2xl:  17px;   /* row titles, ghost button */
    --rk-fs-3xl:  18px;
    --rk-fs-4xl:  20px;   /* primary button, input value */
    --rk-fs-5xl:  22px;   /* app wordmark, chevrons */
    --rk-fs-6xl:  24px;
    --rk-fs-7xl:  34px;   /* page title h1 */

    /*
       HARD FLOOR, NOT A PREFERENCE: never set a text input below 16px.
       iOS Safari zooms the page on focus at anything smaller and never
       zooms back out. Use --rk-fs-input for every text-entry control.
    */
    --rk-fs-input: 16px;

    /* -- TYPE - weights ------------------------------------- */
    --rk-fw-body:     400;
    --rk-fw-medium:   500;
    --rk-fw-semibold: 600;
    --rk-fw-bold:     700;

    /* -- TYPE - tracking. THE SIGNATURE: smaller type, wider track -- */
    --rk-track-2xs:  0.02em;   /* the picker row's top line */
    --rk-track-7xl:  0.04em;   /* 34px */
    --rk-track-5xl:  0.03em;   /* 22px wordmark */
    --rk-track-4xl:  0.06em;
    --rk-track-3xl:  0.08em;
    --rk-track-2xl:  0.10em;   /* buttons - the most common */
    --rk-track-xl:   0.12em;   /* labels */
    --rk-track-lg:   0.14em;   /* small stamps */
    --rk-track-hero: 0.28em;   /* the tiny wide company line */

    /* -- TYPE - line heights -------------------------------- */
    --rk-lh-flat:  1;      /* every chip / stamp / button */
    --rk-lh-tight: 1.15;
    --rk-lh-snug:  1.35;
    --rk-lh-base:  1.45;   /* html/body */
    --rk-lh-prose: 1.62;

    /*
       THE MADLIB SENTENCE LINE HEIGHT, AND IT IS NOT A TYPO.
       Running prose is mixing with 40px inline controls; anything
       tighter and consecutive lines' blanks collide. Nothing else
       in the app needs it and the next rung down is 1.62.
    */
    --rk-lh-sentence: 2.1;

    /*
       THE PROSE MEASURE. Independent of --rk-col on purpose: at
       1280px --rk-col opens to `none`, and a sentence running the
       full width of a dispatcher's monitor is unreadable. Prose
       wants a measure however wide the page is.
    */
    --rk-measure: 62ch;

    /* -- SPACE - 2px base grid ------------------------------ */
    --rk-sp-1:   1px;
    --rk-sp-2:   2px;
    --rk-sp-3:   3px;
    --rk-sp-4:   4px;
    --rk-sp-5:   5px;
    --rk-sp-6:   6px;
    --rk-sp-8:   8px;
    --rk-sp-10: 10px;   /* the most common gap */
    --rk-sp-12: 12px;
    --rk-sp-14: 14px;   /* card bottom margin, page rhythm */
    --rk-sp-16: 16px;   /* page gutter */
    --rk-sp-18: 18px;
    --rk-sp-20: 20px;   /* page top padding */
    --rk-sp-24: 24px;
    --rk-sp-28: 28px;   /* page bottom padding */
    --rk-sp-40: 40px;

    /* -- SHAPE ---------------------------------------------- */
    --rk-corner:        14px;  /* THE diagonal card cut */
    --rk-radius-0:      0;     /* inputs and rows are square, deliberately */
    --rk-radius-xs:     3px;
    --rk-radius-sm:     5px;
    --rk-radius-md:     10px;  /* sheets */
    --rk-radius-pill:   999px;
    --rk-radius-circle: 50%;

    --rk-border-hair: 1px;
    --rk-border-card: 1.5px;
    --rk-border:      2px;   /* the default - inputs, tabs, chips */
    --rk-rail:        5px;   /* the left status rail on a card */
    --rk-btn-edge:    4px;   /* the primary button's bottom edge */

    --rk-stamp-tilt: -3deg;  /* THE stamp. -4deg is the splash mark. */

    /* -- SHADOW - only two exist, and that is correct -------- */
    --rk-shadow-card:  4px 4px 0 rgba(var(--rk-ink-rgb), 0.12);  /* hard, no blur */
    --rk-shadow-float: -12px 0 40px rgba(var(--rk-ink-rgb), 0.25);
    --rk-shadow-drop:  0 18px 40px rgba(var(--rk-ink-rgb), 0.28); /* a centered dialog */

    /* -- MOTION - the app is nearly motionless by design ----- */
    --rk-dur-press: 120ms;
    --rk-dur-ui:    160ms;
    --rk-dur-shimmer: 1.4s;
    --rk-ease:      ease;
    --rk-spin:      0.8s linear infinite;

    /*
       prefers-reduced-motion SLOWS a spinner rather than stopping it - it is the
       only signal that work is happening, and a frozen one says the opposite of
       the truth. This is that slower duration, tokenised so every spinner in the
       kit agrees.
    */
    --rk-dur-reduced: 2.5s;

    /* "Effectively off", for the reduced-motion blanket rule. Not zero, because a zero-length
       animation does not fire its events and some components listen for animationend. */
    --rk-dur-none: 0.01ms;

    /* -- DENSITY / CONTROLS (redefined per breakpoint below) - */
    /* THE MAP BOX. Declared here rather than left to a var() fallback because the design
       gate is right to refuse an undeclared custom property: CSS drops the declaration
       silently, so it renders as "no value set" and looks almost right. RkMap reads both and
       a host overrides either on its own container - a full-height Map Center wants 100%, a
       card-sized mini map wants a fixed box. */
    --rk-map-h:      100%;
    --rk-map-min-h:  22rem;

    --rk-tap:        56px;  /* touch target floor */
    --rk-control-h:  56px;
    --rk-control-md: 44px;  /* the decided middle rung - see the madlib note */
    --rk-control-sm: 40px;  /* tabs, chips, option buttons */
    --rk-control-xs: 34px;  /* jump buttons */
    --rk-row-h:      56px;
    --rk-btn-min:    72px;  /* an inline GO button beside an input */
    --rk-notice-min: 24ch;  /* a notice's words never narrower than this beside its buttons - they wrap under */

    /*
       THE MADLIB BLANK IS DELIBERATELY 40px, NOT --rk-tap.
       A 56px blank on a 2.1 line-height sentence stops reading as
       prose. The painted box stays at --rk-control-sm and the HIT
       area is extended to --rk-control-md by a pseudo-element, so
       a thumb gets 44px without the paragraph turning into a row
       of buttons. Do not "fix" this by raising the height.
    */
    --rk-blank-max: 14em;

    /* -- LAYOUT --------------------------------------------- */
    --rk-col:       520px;     /* the app column */
    --rk-gutter:    16px;
    --rk-dialog-w:  480px;     /* a centered confirm / picker */
    --rk-sheet-h:   84dvh;     /* dvh, never vh - the iOS address bar */
    --rk-scrollbar: 10px;

    /*
       A STACKED TABLE'S LABEL COLUMN. Below 640px a table in RkStackedTable (or an RkTable with
       StackOnPhone) becomes one block per row, each cell a line with its column's header in
       front of it. The labels share this width so the values line up down the card; a longer
       label wraps inside it rather than pushing its value. 7.5rem holds "THEIR INVOICE" and
       "REGULAR PAY" on one line at the label's size and leaves a 390px phone ~200px of value.
    */
    --rk-stack-label: 7.5rem;

    /*
       THE BOARD LANE. A column of a dispatch board, and the first layout the app
       column cannot express: a board is a HORIZONTAL strip of fixed-width piles,
       so the page scrolls sideways and each lane scrolls down.

       320px is the narrowest that still fits a document number, a customer name
       and a wrapped address line without the cards turning into ellipses - the
       measurement that matters, because a dispatcher reads down a column of
       twenty. The height is a MAX, in dvh for the same reason --rk-sheet-h is:
       a short lane stays short, a long one scrolls inside itself and leaves its
       header in view.
    */
    --rk-lane-w:    320px;
    --rk-lane-h:    64dvh;

    /*
       Z-INDEX LADDER - AND IT HAS THREE BANDS, WHICH IS THE PART THAT WAS MISSING.
       NEVER give a layout container a z-index. It becomes a stacking
       context and traps every overlay underneath the app bar.

         BAND 1  BELOW THE BAR - page furniture.   -1 .. 9
         BAND 2  THE APP BAR and what hangs off it.     10
         BAND 3  ABOVE THE BAR - overlays that are
                 ENTITLED to cover the chrome.    40 .. 1000

       🛑 A RUNG BETWEEN 11 AND 39 IS THE BUG, NOT A GAP TO FILL. Anything a
       PAGE paints belongs in band 1. The app bar is the ceiling of page
       content, and the only things allowed through it are a modal, the error
       bar, a toast and the file viewer - each of which covers the bar on
       purpose. A sticky page header that outranks the bar does not look like a
       z-index bug from the outside: it looks like the nav menu is broken.
    */

    /* ---- BAND 1: BELOW THE BAR. Page furniture, and it stays page furniture. */
    --rk-z-crest:   -1;

    /*
       A PAGE'S OWN STICKY HEADER - a table's <th> row, a builder's refusal band.

       ⚠️ IT IS 1, AND IT WAS 20, AND THE DIFFERENCE IS A BUG KIRK REPORTED FROM A
       SCREENSHOT. At 20 it outranked --rk-z-bar, so on /integrations the dark
       RkTable header band painted straight THROUGH the open OPS dropdown and ate
       its lower half - NUMBERING down to CONTROL KIT. Measured in the browser
       rather than reasoned about: elementFromPoint inside the open panel, on the
       header's line, returned TH.rk-table__th, so the menu was not merely painted
       under - it could not be clicked either.

       AND THE VALUE IS NOT THE WHOLE STORY. RkTable's own comment called this "a
       LOCAL stacking value inside an already-scrolling container". It is not
       local: every ancestor from the <th> up to <body> is position:static /
       z-index:auto, so there is no stacking context between them and the root and
       the 20 competed with the app bar directly. The wrapper must NOT be given one
       either - that warning below is still right, because overlays open from inside
       a row. So the sticky rung has to be low, and low is all it ever needed: 1
       already beats the table's own rows, which are static.
    */
    --rk-z-substick: 1;

    /* ---- BAND 2: THE APP BAR. The ceiling of everything a page draws. */
    --rk-z-bar:     10;

    /*
       ---- IN THE FORBIDDEN RANGE, KNOWINGLY, AND NOT FIXED HERE.

       A field's own hint popover and its invisible click-away layer. Above a sub-sticky
       header, below the scrim - a tip must never outrank a dialog. Both of those still
       hold; what was never considered is the BAR.

       ⚠️ 30 IS BETWEEN 11 AND 39, WHICH THE NOTE ABOVE CALLS A BUG, AND IT IS ONE.
       Its only consumers today are RkMap's veil, its refusal sheet and its hover card
       (RkField's hint uses the native top layer and carries no z-index at all). Those
       three sit above map chrome drawn at --rk-z-bar, so simply lowering this rung
       would put the veil UNDER the zoom buttons - which is why it is left alone rather
       than dropped to match --rk-z-substick.

       THE FIX IS ONE LINE IN RkMap.razor.css: `isolation: isolate` on .rk-map. It costs
       nothing and traps nothing, because .rk-map is ALREADY overflow:hidden, so its
       children cannot escape the box today either. That makes the map's whole ladder
       local, after which this rung belongs in band 1.

       UNTIL THEN: .rk-map is not a stacking context, so where a scrolled map's box
       passes under the sticky bar, a raised veil or an open hover card paints on top of
       the app bar.
    */
    --rk-z-pop:     30;

    /* ---- BAND 3: ABOVE THE BAR, DELIBERATELY. */
    --rk-z-scrim:   40;
    --rk-z-sheet:   41;
    --rk-z-sheet2:  60;
    --rk-z-confirm: 61;
    --rk-z-chrome: 200;
    --rk-z-toast:  300;
    --rk-z-viewer:1000;

    /* -- DECORATION (the crest watermark) ------------------- */
    --rk-crest-strength: 0.10;
    --rk-card-veil:      0.55;   /* WCAG-measured; 0.42 is the AAA floor */
}

/* ============================================================
   LIGHT ISLAND.

   Every token the dark blocks below override, restated, so a
   subtree marked data-theme="light" is fully light even when the
   page around it is dark. Gated against :root by
   DesignSystemTests - if you change a colour above and not here,
   the build fails.
   ============================================================ */
[data-theme="light"] {
    color-scheme: light;
    --rk-paper:         #f3efe6;
    --rk-card:          #fffdf7;
    --rk-white:         #ffffff;
    --rk-field:         #ffffff;
    --rk-ink:           #16232d;
    --rk-ink-deep:      #000000;
    --rk-ink-soft:      #3c4c58;
    --rk-steel:         #4e6e81;
    --rk-placeholder:   #8f8878;
    --rk-line:          #d9d2c0;
    --rk-line-hard:     #b9b09a;
    --rk-accent:        #e8590c;
    --rk-accent-deep:   #b23e00;
    --rk-accent-soft:   #fdeee3;
    --rk-ok:            #2b8a3e;
    --rk-ok-soft:       #edf4e7;
    --rk-danger:        #c92a2a;
    --rk-danger-soft:   #fdecec;
    --rk-danger-deep:   #7d1a1a;
    --rk-warn:          #e8590c;
    --rk-warn-soft:     #fdeee3;
    --rk-on-fill:       #ffffff;
    --rk-accent-ink:    #b23e00;
    --rk-ok-ink:        #1e6b2c;
    --rk-danger-ink:    #7d1a1a;
    --rk-warn-ink:      #b23e00;
    --rk-disabled:      #a9a293;
    --rk-disabled-deep: #8d8677;
    --rk-disabled-text: #98917f;
    --rk-chrome-bg:     #16232d;
    --rk-ink-rgb:    22, 35, 45;
    --rk-paper-rgb:  243, 239, 230;
    --rk-card-rgb:   255, 253, 247;
    --rk-shadow-card: 4px 4px 0 rgba(var(--rk-ink-rgb), 0.12);
}

/* ============================================================
   DENSITY - opt-in, independent of viewport width.
   A grid-heavy desktop screen sets data-density="compact" on a
   container; a phone stays at the touch-target default.
   ============================================================ */
[data-density="comfortable"] { --rk-control-h: 40px; --rk-row-h: 40px; --rk-tap: 40px; }
[data-density="compact"]     { --rk-control-h: 32px; --rk-row-h: 30px; --rk-tap: 32px; }

/* ============================================================
   BREAKPOINTS
   The source app is a phone-only technician app and has NONE of
   these. RIPROKA must be equally good on a dispatcher's desktop,
   so the column opens up and controls tighten as width allows.
   ============================================================ */
@media (min-width: 640px) {
    :root { --rk-col: 640px; }
}

@media (min-width: 900px) {
    :root {
        --rk-col: 860px;
        --rk-gutter: 20px;
        --rk-control-h: 40px;
        --rk-row-h: 40px;
    }
}

@media (min-width: 1280px) {
    :root { --rk-col: none; --rk-gutter: 24px; }
}

@media (min-width: 1680px) {
    :root { --rk-gutter: 32px; }
}

/* ============================================================
   DARK THEME.

   The colour values came over as a PROPOSAL and are now partly
   measured: ThemeContrastTests gates body text, the chrome pair
   and the tinted row states in both themes, and DesignSystemTests
   gates every pair the control kit actually paints.

   ⚠️ STILL KNOWN-BAD AND DELIBERATELY LEFT ALONE:
   --rk-white on --rk-accent / --rk-ok / --rk-danger measures
   2.05 / 2.18 / 2.75 in dark, against a 3:1 floor. The fix is NOT
   to move these hexes - ThemeContrastTests asserts the failure as
   the current state on purpose - it is that no control paints
   that pair. Text on a fill is --rk-on-fill. See the ink note in
   the :root block.
   ============================================================ */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;
        --rk-paper:       #14191d;
        --rk-card:        #1b2228;
        --rk-white:       #e9e4d8;
        --rk-field:       #0f1519;
        --rk-ink:         #e9e4d8;
        --rk-ink-deep:    #ffffff;
        --rk-ink-soft:    #a9b4bc;
        --rk-steel:       #8aa6b6;
        --rk-placeholder: #6b7278;
        --rk-line:        #2c353c;
        --rk-line-hard:   #3f4a52;
        --rk-accent:      #ff7a33;
        --rk-accent-deep: #c9561a;
        --rk-accent-soft: #2e2019;
        --rk-ok:          #4caf5a;
        --rk-ok-soft:     #1c2a1e;
        --rk-danger:      #ef5350;
        --rk-danger-soft: #2c1a1a;
        --rk-danger-deep: #ffb4b0;
        --rk-warn:        #ff7a33;
        --rk-warn-soft:   #2e2019;
        --rk-on-fill:     #14191d;
        --rk-accent-ink:  #ff7a33;
        --rk-ok-ink:      #4caf5a;
        --rk-danger-ink:  #ffb4b0;
        --rk-warn-ink:    #ff7a33;
        --rk-disabled:      #4a5259;
        --rk-disabled-deep: #383f45;
        --rk-disabled-text: #8b949c;
        --rk-ink-rgb:     233, 228, 216;
        --rk-paper-rgb:    20,  25,  29;
        --rk-card-rgb:     27,  34,  40;
        --rk-shadow-card: 4px 4px 0 rgba(0, 0, 0, 0.45);

        /* Chrome goes deeper in dark, never lighter. It must stay a dark
           surface so --rk-chrome-ink remains readable on it. */
        --rk-chrome-bg:   #0d1419;
    }
}

/* The explicit toggle, and the DARK ISLAND. Kept as its own block
   rather than folded into the media query above so the media query
   can be removed entirely if RIPROKA ever decides theme is a user
   setting only. The bare [data-theme="dark"] half is what lets a
   panel inside a light page render dark. */
:root[data-theme="dark"],
[data-theme="dark"] {
    color-scheme: dark;
    --rk-paper:       #14191d;
    --rk-card:        #1b2228;
    --rk-white:       #e9e4d8;
    --rk-field:       #0f1519;
    --rk-ink:         #e9e4d8;
    --rk-ink-deep:    #ffffff;
    --rk-ink-soft:    #a9b4bc;
    --rk-steel:       #8aa6b6;
    --rk-placeholder: #6b7278;
    --rk-line:        #2c353c;
    --rk-line-hard:   #3f4a52;
    --rk-accent:      #ff7a33;
    --rk-accent-deep: #c9561a;
    --rk-accent-soft: #2e2019;
    --rk-ok:          #4caf5a;
    --rk-ok-soft:     #1c2a1e;
    --rk-danger:      #ef5350;
    --rk-danger-soft: #2c1a1a;
    --rk-danger-deep: #ffb4b0;
    --rk-warn:        #ff7a33;
    --rk-warn-soft:   #2e2019;
    --rk-on-fill:     #14191d;
    --rk-accent-ink:  #ff7a33;
    --rk-ok-ink:      #4caf5a;
    --rk-danger-ink:  #ffb4b0;
    --rk-warn-ink:    #ff7a33;
    --rk-disabled:      #4a5259;
    --rk-disabled-deep: #383f45;
    --rk-disabled-text: #8b949c;
    --rk-ink-rgb:     233, 228, 216;
    --rk-paper-rgb:    20,  25,  29;
    --rk-card-rgb:     27,  34,  40;
    --rk-shadow-card: 4px 4px 0 rgba(0, 0, 0, 0.45);
    --rk-chrome-bg:   #0d1419;
}

/* ============================================================
   PRINT.

   Work orders and invoices get printed. Overriding the tokens is
   the whole mechanism - every component already reads them, so
   nothing else in the kit needs a print rule. These are the only
   raw hex values outside the theme blocks and they live here
   rather than in rk-base.css precisely so the "no raw colour
   outside rk-tokens.css" gate stays absolute.
   ============================================================ */
@media print {
    :root,
    :root[data-theme="dark"],
    [data-theme="dark"],
    [data-theme="light"] {
        --rk-paper:      #ffffff;
        --rk-card:       #ffffff;
        --rk-field:      #ffffff;
        --rk-ink:        #000000;
        --rk-ink-soft:   #000000;
        --rk-on-fill:    #ffffff;
        --rk-chrome-bg:  #000000;
        --rk-chrome-ink: #ffffff;
        --rk-shadow-card: none;
    }
}
