/* ==========================================================================
   themes.css — every colour in the application, for both themes.

   Nothing outside this file may contain a hex / rgb value. Component CSS
   only ever references a semantic token, so a theme is a data change, not
   a code change.

   The theme is selected by an attribute on <html>, written by js/theme.js
   before the stylesheets paint:

       <html data-theme="light">   or   <html data-theme="dark">

   Light is also the fallback on :root so the page is never unstyled if the
   attribute is missing for any reason.
   ========================================================================== */

/* ==========================================================================
   LIGHT — the default working theme.
   A neutral cool-grey canvas, white work surfaces, a Tournate-blue sidebar
   matching the login brand, and a restrained blue accent.
   ========================================================================== */
:root,
[data-theme="light"] {
  color-scheme: light;

  /* --- surfaces --- */
  --tn-app-bg:              #eceff4;
  --tn-surface:             #ffffff;
  --tn-surface-raised:      #f8fafc;   /* panel headers, toolbars           */
  --tn-surface-sunken:      #f1f4f9;   /* inert areas                       */
  --tn-surface-overlay:     #ffffff;   /* menus, modals, drawers            */
  --tn-surface-accent-soft: #e9f1fb;

  /* --- borders ---

     THREE STRUCTURAL WEIGHTS, AND A SEPARATE FAMILY FOR CONTROLS.

       --tn-border          the ordinary structural separator: panel edges,
                            grid rules, dialog dividers
       --tn-border-strong   a separator that has to carry more weight than
                            the one beside it — a grid header's underline,
                            a column-group boundary
       --tn-border-subtle   a separator inside an already-bounded area

     A FORM CONTROL'S BOUNDARY IS NOT A STRUCTURAL SEPARATOR, and has its
     own three below: --tn-input-border, --tn-input-border-hover and the
     disabled pair. --tn-border-strong and --tn-input-border currently hold
     the same value; they are NOT interchangeable, and a hover rule that
     reached for --tn-border-strong instead of --tn-input-border-hover is
     precisely how every input in the product came to have a hover state
     that painted nothing. Same value, different role. */
  --tn-border:              #dde3ec;
  --tn-border-strong:       #c3ccdb;
  --tn-border-subtle:       #e9edf4;

  /* --- text --- */
  --tn-text:                #17212f;
  --tn-text-secondary:      #47546a;
  /* Muted still carries real content — record codes, panel subtitles,
     secondary cell lines — so it must clear 4.5:1 on the sunken surface,
     not just look quiet. */
  --tn-text-muted:          #5a6779;
  --tn-text-inverse:        #ffffff;
  --tn-text-link:           #1c5aa8;
  --tn-text-on-accent:      #ffffff;
  --tn-on-accent-soft:      rgba(255, 255, 255, 0.45);

  /* --- accent --- */
  --tn-accent:              #1f5fb0;
  --tn-accent-hover:        #17508f;
  --tn-accent-active:       #123f73;
  --tn-accent-soft:         #e6eefa;
  --tn-accent-soft-hover:   #d8e5f7;
  --tn-accent-border:       #b9d0ee;

  /* --- semantic --- */
  --tn-success:             #1c7a4d;
  --tn-success-soft:        #e4f3ea;
  --tn-success-border:      #b7dfc8;

  --tn-warning:             #96620f;
  --tn-warning-soft:        #fbf0dc;
  --tn-warning-border:      #ecd3a4;

  --tn-danger:              #ab2b2b;
  --tn-danger-hover:        #8f2222;
  --tn-danger-soft:         #fae9e9;
  --tn-danger-border:       #eec4c4;

  --tn-info:                #1c6b86;
  --tn-info-soft:           #e4f0f5;
  --tn-info-border:         #b6d7e2;

  --tn-neutral-soft:        #eef1f6;
  --tn-neutral-border:      #d6dce6;

  /* --- charts ------------------------------------------------------------
     A six-colour categorical series for the dashboard. Ordered so the first
     three carry most of the work and stay inside the Tournate register:
     the brand blue, an operations green, then amber. Purple, teal and rose
     only appear once a chart genuinely has that many categories.

     They are deliberately NOT the semantic tokens: --tn-success means "this
     is good", while chart 2 means "this is the second category". Reusing the
     semantic ones would make every green segment read as a status. */
  --tn-chart-1:             #2f6fd0;   /* blue   — the brand series        */
  --tn-chart-2:             #1f9d6b;   /* green                            */
  --tn-chart-3:             #d98324;   /* amber                            */
  --tn-chart-4:             #7b5cd6;   /* purple                           */
  --tn-chart-5:             #1f8fa8;   /* teal                             */
  --tn-chart-6:             #cf4b5c;   /* rose                             */

  /* Fills sit under strokes, so they are the same hue at low alpha rather
     than a separate lighter colour — an area chart then reads as one object. */
  --tn-chart-1-soft:        rgba(47, 111, 208, 0.16);
  --tn-chart-2-soft:        rgba(31, 157, 107, 0.16);
  --tn-chart-3-soft:        rgba(217, 131, 36, 0.16);
  --tn-chart-4-soft:        rgba(123, 92, 214, 0.16);
  --tn-chart-5-soft:        rgba(31, 143, 168, 0.16);
  --tn-chart-6-soft:        rgba(207, 75, 92, 0.16);

  /* Chart furniture: quiet enough that the data is the only thing read. */
  --tn-chart-grid:          #e6ebf3;
  --tn-chart-axis:          #6b7688;
  --tn-chart-track:         #e9edf4;   /* unfilled bar / ring remainder    */
  --tn-chart-compare:       #9fb0c8;   /* the "last period" reference line */

  /* --- focus ---
     Two shapes of one idea. Bordered controls (buttons, inputs, chips) take
     the ring, because they already have an edge to tint. Everything else —
     links, checkboxes, the info control, a preference segment — takes the
     outline, because there is no border to work with.

     --tn-focus-outline is the fallback the global :focus-visible rule in
     layout.css applies to anything with no focus style of its own. It was
     REFERENCED but never DEFINED, which voided that declaration and left
     breadcrumb links, .link-btn and the skip link with no visible focus at
     all. Defining it here is what turns the global rule back on. */
  --tn-focus-ring:          0 0 0 3px rgba(31, 95, 176, 0.20);
  --tn-focus-ring-danger:   0 0 0 3px rgba(171, 43, 43, 0.28);
  --tn-focus-outline-color: #1f5fb0;
  --tn-focus-outline:       2px solid #1f5fb0;

  /* --- sidebar: the Tournate blue family, anchored on #507eb8 ---
     The authenticated continuation of the login brand panel. The panel's
     gradient runs #123f86 -> #2c67ae -> #507eb8; the sidebar takes a SOLID
     surface from the middle of that run, so the two read as one product
     without the sidebar borrowing the login's gradient or its glow.

     A flat surface, not a gradient: this one is looked at for eight hours,
     and depth here comes from the states rather than from the background.
     Hover and active step lighter toward the #507eb8 anchor, which the logo
     tile still carries outright. Every foreground below clears 4.5:1 on the
     surface it actually sits on. */
  --tn-side-bg:             #2f5f9b;
  --tn-side-bg-raised:      #27538a;
  --tn-side-border:         #4076ad;
  --tn-side-text:           #eaf2fc;   /* 5.8:1 on the surface            */
  --tn-side-text-muted:     #c8dcf1;   /* 4.6:1 - secondary, still legible */
  --tn-side-text-strong:    #ffffff;
  --tn-side-hover-bg:       #3a6ca7;
  --tn-side-active-bg:      #4576b0;   /* white on it: 4.7:1              */
  --tn-side-active-bar:     #a9d9fb;
  --tn-side-focus-ring:     rgba(169, 217, 251, 0.35);
  --tn-side-logo-bg:        #507eb8;   /* the anchor, unchanged           */

  /* --- data grid --- */
  --tn-grid-head-bg:          #f2f5fa;
  --tn-grid-head-text:        #3b4860;
  --tn-grid-border:           #e4e9f1;
  --tn-grid-row-hover:        #f4f8fd;
  --tn-grid-row-alt:          #fbfcfe;
  --tn-grid-row-selected:     #e3eefc;
  --tn-grid-row-selected-bar: #1f5fb0;
  --tn-grid-row-focus:        #d7e7fb;

  /* --- form controls --- */
  --tn-input-bg:            #ffffff;
  --tn-input-bg-disabled:   #f1f4f9;
  --tn-input-border:        #c3ccdb;
  /* A real step darker than the resting border. It used to point at
     --tn-border-strong, which holds the same value as --tn-input-border,
     so every input in the product had a hover rule that painted nothing. */
  --tn-input-border-hover:  #a7b3c6;
  --tn-input-text:          #17212f;
  /* A placeholder is real guidance, not decoration, so it clears 4.5:1 on the
     white input rather than sitting at the 3.7:1 a lighter grey gave. Same
     cool grey-blue family, one step down in value. */
  --tn-input-placeholder:   #6a7788;
  /* An invalid field is repainted with --tn-danger-soft, and the ordinary
     placeholder only reaches 3.9:1 on that warmer ground. This is the same
     hint in the danger family: 4.8:1 on the invalid fill, and restrained
     enough that it still reads as a placeholder rather than as the error
     message underneath. Shared by every invalid input, not just Login. */
  --tn-input-placeholder-invalid: #8c5a5a;

  /* --- global chrome: the top bar is its own surface so it reads as
         application chrome rather than as page content --- */
  --tn-topbar-bg:           #ffffff;
  --tn-topbar-border:       #d7dee9;

  /* Top bar branding. The supplied Tournate mark is a pure-white SVG, so the
     light theme points at a navy variant of the same geometry rather than
     filtering white to dark. The customer mark is already navy and needs no
     treatment here. */
  --tn-logo-tournate:        url("../assets/tournate-logo-navy.svg");
  --tn-logo-customer-filter: none;
  --tn-topbar-brand-divider: #d5dce7;
  --tn-context-bg:          #f6f8fb;
  --tn-context-bg-hover:    #eef2f8;
  --tn-context-border:      #d7dee9;
  --tn-search-mark-bg:      #dbeafe;

  /* Unsaved-changes indicator */
  --tn-dirty-bg:            #fbf0dc;
  --tn-dirty-border:        #ecd3a4;
  --tn-dirty-text:          #96620f;

  /* --- Hot Fix: the grid is being typed into directly -------------------
     Its own semantic name on the amber family the unsaved-changes flag
     already uses, because it is the same idea one step further on: work in
     progress that has not settled yet. Deliberately NOT the danger family —
     a correction at the counter is an ordinary operation and a red grid
     would read as "something has gone wrong", which is a different sentence
     entirely. Deliberately not the accent family either, because accent is
     what selection, focus and every primary action already mean. */
  --tn-hotfix:              #96620f;
  --tn-hotfix-strong:       #7a4f0c;
  --tn-hotfix-soft:         #fdf6e9;
  --tn-hotfix-soft-strong:  #fbf0dc;
  --tn-hotfix-border:       #d9ad5e;
  /* The halo around a panel in Hot Fix. A ring, not a shadow: it says "this
     one" without lifting the panel off the workspace. */
  --tn-hotfix-ring:         rgba(150, 98, 15, 0.16);
  --tn-hotfix-cell-bg:      #fffaf0;
  --tn-hotfix-new-bg:       #fdf6e9;

  /* --- guidance: "the control you want next is this one" ----------------
     A three-second ring on an enabled control. It is the accent family, not
     a warning: nothing is wrong, there is simply a next step. */
  --tn-guide-ring:          rgba(31, 95, 176, 0.34);
  --tn-guide-ring-wide:     rgba(31, 95, 176, 0.14);

  /* --- dialogs ----------------------------------------------------------
     A dialog is the application's own surface lifted off the workspace, not
     a card floating in a void, so it borrows the overlay surface and the
     panel's header tone rather than inventing a palette. What it adds is a
     slightly firmer header ground and a scrim deep enough that a dense form
     over a dense grid still reads as one thing at a time. */
  --tn-dlg-bg:              var(--tn-surface-overlay);
  --tn-dlg-head-bg:         var(--tn-surface-raised);
  --tn-dlg-foot-bg:         var(--tn-surface-raised);
  --tn-dlg-border:          var(--tn-border);
  --tn-dlg-scrim:           rgba(13, 22, 38, 0.52);
  --tn-dlg-shadow:          0 8px 24px rgba(20, 33, 51, 0.14),
                            0 32px 72px rgba(20, 33, 51, 0.22);

  /* A boxed sub-surface inside a form — the Calculation block, a weekday
     cluster. One step sunken, never a second card with its own shadow. */
  --tn-dlg-inset-bg:        #f7f9fc;
  --tn-dlg-inset-border:    var(--tn-border);

  /* The supporting palette: same family, lighter presence, no scrim. */
  --tn-dlg-tool-shadow:     0 4px 12px rgba(20, 33, 51, 0.12),
                            0 18px 40px rgba(20, 33, 51, 0.18);

  /* --- the page tour ----------------------------------------------------
     A dimmer that quiets the page without hiding it — an operator has to be
     able to recognise the panel being described from the shape of the one
     next to it, so this is deliberately lighter than the dialog scrim.

     The ring is the accent family. Not the Hot Fix amber, which means "you
     are editing", and not the danger family: a tour is neither a warning
     nor a mode that changes data. */
  --tn-tour-scrim:          rgba(13, 22, 38, 0.42);
  --tn-tour-ring:           #1f5fb0;
  --tn-tour-ring-glow:      rgba(31, 95, 176, 0.30);
  --tn-tour-mark-bg:        var(--tn-surface-overlay);
  --tn-tour-mark-border:    var(--tn-border);
  --tn-tour-mark-shadow:    0 6px 18px rgba(20, 33, 51, 0.16),
                            0 24px 56px rgba(20, 33, 51, 0.22);

  /* The mock document editor. Its canvas is paper, in both themes — an
     e-mail is composed on the ground it will be read on. */
  --tn-editor-bg:           #ffffff;
  --tn-editor-text:         #1b2432;
  --tn-editor-border:       var(--tn-border);
  --tn-editor-bar-bg:       var(--tn-surface-raised);
  --tn-editor-token-bg:     #e6eefa;
  --tn-editor-token-border: #b9d0ee;
  --tn-editor-token-text:   #1c5aa8;

  /* --- login brand panel ---
         The supplied Tournate logo is pure white on transparent, so the brand
         panel is dark in BOTH themes. These tokens exist in both blocks so the
         page never depends on which theme is active. */
  --tn-login-page-bg:       #eef1f6;
  /* The right half is a calm near-white ground; the form surface itself is
     pure white, so the card reads as lifted off it rather than floating in
     a void. */
  --tn-login-panel-bg:      var(--tn-surface-sunken);
  --tn-login-form-bg:       #ffffff;
  --tn-login-surface-border: #e2e8f1;
  --tn-login-surface-shadow: 0 1px 2px rgba(16, 32, 56, 0.05),
                             0 14px 34px rgba(16, 32, 56, 0.08);

  /* Tournate blue. #507eb8 is the anchor and carries the brightest corner of
     the panel; the gradient starts from a deeper tone of the same family so
     the white logo (top-left) keeps ~8:1 contrast. */
  /* Deeper and richer than before, but still the approved family: #507eb8
     remains the anchor and carries the open lower-right corner, while the
     upper-left goes to a deep royal tone so the white logo has real depth
     behind it. The bright azure in the composition is the travelling light,
     not the base gradient. */
  --tn-login-brand-from:    #123f86;
  --tn-login-brand-mid:     #2c67ae;
  --tn-login-brand-to:      #507eb8;
  --tn-login-glow:          rgba(137, 189, 233, 0.26);
  /* The ground. The panel used to run out of tone below its midpoint and
     end on a pale wash exactly where the footer line sits; this is the
     weight that carries the composition to the bottom edge. Anchored off
     centre and below the panel, so it grounds the copy column without
     reading as a symmetrical vignette. */
  --tn-login-ground:        rgba(6, 28, 68, 0.76);
  --tn-login-ground-fade:   rgba(6, 28, 68, 0);
  --tn-login-glow-accent:   rgba(99, 198, 214, 0.18);
  --tn-login-accent-rule:   rgba(138, 205, 255, 0.92);

  /* --- brand panel atmosphere: DIRECTIONAL SUNLIGHT -------------------
     ONE source, entering from beyond the top-right corner and sifting down
     across the blue. Every layer is centred on the same point outside the
     panel — 106% -10% — and differs only in how far it reaches, so they
     read as one light at four depths rather than as four glows. The
     previous version placed seven fields at seven origins, which is exactly
     what made it look like scattered ambient blobs.

     The origin sits OFF the panel on purpose. A radial gradient centred
     inside the frame always shows its middle, and a bright middle on a
     gradient is a sun disc; with the centre outside, only the spread is
     ever visible and the light has a direction instead of a location.

     far     the throw — reaches almost to the far corner, very gradual
     mid     the body of the wash
     near    the concentration closest to where the light enters
     accent  the sift: what is left of the light after it has crossed the
             panel, low and cool, deliberately subordinate

     Warm near the source, cooling as it travels — that temperature shift
     over distance is what makes it read as sunlight rather than as a white
     glow. Every stop fades through its own hue, never through `transparent`,
     which interpolates via transparent black and would leave a grey rim. */
  --tn-login-veil-far:
    radial-gradient(154% 128% at 106% -10%,
      rgba(255, 243, 216, 0.30) 0%, rgba(255, 243, 216, 0) 74%);

  --tn-login-veil-mid:
    radial-gradient(94% 80% at 104% -6%,
      rgba(255, 246, 224, 0.30) 0%, rgba(255, 246, 224, 0) 62%);

  --tn-login-veil-near:
    radial-gradient(56% 50% at 102% -3%,
      rgba(255, 251, 238, 0.34) 0%, rgba(255, 251, 238, 0) 64%);

  /* The far end of the same light: cool, wide and very low, sitting where
     the wash finally runs out. It is the only layer not on the source axis,
     because it is not a source — it is the tail. */
  --tn-login-veil-accent:
    radial-gradient(78% 58% at 62% 92%,
      rgba(214, 234, 255, 0.14) 0%, rgba(214, 234, 255, 0) 70%);
  /* Arc strokes: thin, quiet, decorative. Deliberately far below the light
     so geometry and illumination never read as the same object. */
  --tn-login-ring:          rgba(255, 255, 255, 0.10);
  --tn-login-ring-strong:   rgba(255, 255, 255, 0.17);
  --tn-login-shade:         rgba(4, 22, 58, 0.60);
  --tn-login-brand-text:    rgba(255, 255, 255, 0.96);
  --tn-login-brand-muted:   rgba(255, 255, 255, 0.90);
  --tn-login-brand-faint:   rgba(255, 255, 255, 0.76);

  /* --- integration logo tiles -------------------------------------------
     Nine of the twenty partner logos are drawn in black or deep navy, so on
     a blue panel they are not merely quiet, they are gone. The tile is the
     surface that gives them somewhere to sit, and it is the ONLY part of
     this feature that is themed — no logo is ever recoloured or tinted.

     Not quite opaque, so the sunlight wash crossing the panel carries on
     through the tile instead of stopping dead at its edge. It composites to
     about #f2f6fa here, on which the nine deep marks measure 8.9:1 or
     better and no logo's strongest ink falls under 3.3:1.

     No visible rim: a lighter-than-white edge cannot be seen and a darker
     one draws a halo, so the border stays a hairline of near-tile white and
     the seating is done entirely by one soft layered shadow in the panel's
     own deep tone. */
  --tn-login-integration-bg:      rgba(255, 255, 255, 0.94);
  --tn-login-integration-border:  rgba(255, 255, 255, 0.72);
  --tn-login-integration-shadow:  0 1px 2px rgba(5, 24, 60, 0.16),
                                  0 10px 24px -8px rgba(5, 24, 60, 0.32);

  /* Decorative travel layer (see the fenced section in login.css) */
  --tn-login-ornament:      rgba(255, 255, 255, 0.17);
  --tn-login-ornament-soft: rgba(255, 255, 255, 0.11);
  --tn-login-route:         rgba(255, 255, 255, 0.24);

  /* --- login: form side, controls and typography -------------------------
     Semantic login tokens so login.css never names a raw colour of its own.
     In LIGHT they alias the application tokens the approved composition
     already used, so the light screen is byte-for-byte the same design. */

  /* Ambient glow behind the FORM half. Light keeps its clean near-white
     ground, so every stop is fully transparent and nothing is painted.
     Stops fade through their OWN hue rather than `transparent`, which
     interpolates via transparent black and leaves a grey rim. */
  --tn-login-ambient-a:     rgba(80, 126, 184, 0);
  --tn-login-ambient-b:     rgba(80, 126, 184, 0);
  --tn-login-ambient-fade:  rgba(80, 126, 184, 0);

  --tn-login-divider:        var(--tn-border-subtle);
  --tn-login-text:           var(--tn-text);
  --tn-login-text-secondary: var(--tn-text-secondary);
  --tn-login-text-muted:     var(--tn-text-muted);

  /* Inputs on the login card */
  --tn-login-input-bg:           var(--tn-input-bg);
  --tn-login-input-border:       var(--tn-input-border);
  --tn-login-input-border-hover: var(--tn-input-border-hover);
  --tn-login-input-text:         var(--tn-input-text);
  --tn-login-input-placeholder:  var(--tn-input-placeholder);
  --tn-login-input-icon:         var(--tn-text-muted);

  /* Preference control surface — the Theme / Language row. The same
     language as the application's .segmented control: sunken track, lifted
     selected segment, accent ink on the selection. */
  --tn-login-control-bg:              var(--tn-surface-sunken);
  --tn-login-control-hover-bg:        #e7edf7;
  --tn-login-control-border:          var(--tn-border);
  --tn-login-control-text:            var(--tn-text-secondary);
  --tn-login-control-selected-bg:     var(--tn-surface);
  --tn-login-control-selected-border: #c9d9ef;
  --tn-login-control-selected-text:   var(--tn-accent);
  --tn-login-control-selected-shadow: var(--tn-shadow-xs);

  /* --- misc --- */
  --tn-scrim:               rgba(13, 22, 38, 0.45);
  --tn-switch-track:        #c3ccdb;
  --tn-switch-knob:         #ffffff;
  --tn-skeleton-a:          #f1f4f9;
  --tn-skeleton-b:          #e3e8f0;

  /* THE VEIL — what a region wears while it is busy.

     Deliberately NOT --tn-scrim. A scrim is for a modal: it darkens the
     page to say "attend to this instead". A veil sits over content the
     user is still reading and must keep it legible while making it
     plainly not-current — so it is the surface colour at high alpha
     rather than ink at low alpha. Rendering it as ink is what makes a
     refreshing table look broken instead of busy. */
  --tn-veil:                rgba(255, 255, 255, 0.72);
  --tn-veil-strong:         rgba(255, 255, 255, 0.90);

  /* THE DROP SURFACE. A dashed border is the one place in this design
     system where a dashed border earns its keep: it is the universal
     "put something here" and inventing a quieter signal for it would be
     originality nobody asked for. It brightens when a file is over it. */
  --tn-drop-border:         var(--tn-border-strong);
  --tn-drop-border-over:    var(--tn-accent);
  --tn-drop-bg:             var(--tn-surface-sunken);
  --tn-drop-bg-over:        var(--tn-accent-soft);

  /* The unfilled part of a progress bar borrows the chart track, which is
     the same idea in the same visual weight; the fill is the accent, so a
     determinate bar reads as the same family as everything else the app
     fills up. */
  --tn-progress-track:      var(--tn-chart-track);
  --tn-progress-fill:       var(--tn-accent);

  /* Themed scrollbars: browser-default bars are the loudest raw cue in
     a dense grid application. */
  --tn-scrollbar-thumb:       #c4cdda;
  --tn-scrollbar-thumb-hover: #a9b4c5;

  /* --- elevation --- */
  /* Layered and soft: a tight contact shadow plus a wide diffuse one.
     Used sparingly - most separation still comes from surface contrast. */
  --tn-shadow-xs: 0 1px 2px rgba(20, 33, 51, 0.06);
  --tn-shadow-sm: 0 1px 2px rgba(20, 33, 51, 0.06), 0 2px 8px rgba(20, 33, 51, 0.06);
  --tn-shadow-md: 0 2px 6px rgba(20, 33, 51, 0.08), 0 12px 28px rgba(20, 33, 51, 0.12);
  --tn-shadow-lg: 0 4px 12px rgba(20, 33, 51, 0.10), 0 24px 56px rgba(20, 33, 51, 0.18);
}

/* ==========================================================================
   DARK — a designed counterpart, not an inversion.

   Principles applied:
     - the canvas is the darkest layer and surfaces lift out of it, so the
       depth order matches the light theme instead of reversing it
     - no pure black and no saturated neon; the family stays blue-charcoal
     - the accent is lightened (#5b9bf0) because #1f5fb0 fails contrast on
       a dark surface
     - "soft" semantic backgrounds become deep tints of their hue rather
       than pale washes
     - borders carry more of the structure, since shadows read weakly on dark
   ========================================================================== */
[data-theme="dark"] {
  color-scheme: dark;

  /* --- surfaces --- */
  --tn-app-bg:              #0e141c;
  --tn-surface:             #161d27;
  --tn-surface-raised:      #1c2531;   /* panel headers, toolbars           */
  --tn-surface-sunken:      #121924;   /* inert areas                       */
  --tn-surface-overlay:     #1e2733;   /* menus, modals, drawers            */
  --tn-surface-accent-soft: #16283f;

  /* --- borders --- */
  --tn-border:              #2a3441;
  --tn-border-strong:       #3c4859;
  --tn-border-subtle:       #232c38;

  /* --- text --- */
  --tn-text:                #e7ecf3;
  --tn-text-secondary:      #aeb9c9;
  --tn-text-muted:          #8a96a8;
  --tn-text-inverse:        #0e141c;
  --tn-text-link:           #7db0f4;
  /* The dark theme lightens the accent, so the ink on it has to go dark:
     white on that fill measures 2.84:1. Covers primary, danger and the
     notification badge in one place. */
  --tn-text-on-accent:      #0b1523;
  --tn-on-accent-soft:      rgba(11, 21, 35, 0.45);

  /* --- accent --- */
  --tn-accent:              #5b9bf0;
  --tn-accent-hover:        #7db0f4;
  --tn-accent-active:       #9cc4f7;
  --tn-accent-soft:         #1a2d47;
  --tn-accent-soft-hover:   #21395a;
  --tn-accent-border:       #33507d;

  /* --- semantic --- */
  --tn-success:             #4cbd88;
  --tn-success-soft:        #142c22;
  --tn-success-border:      #255140;

  --tn-warning:             #e0a94f;
  --tn-warning-soft:        #2e2414;
  --tn-warning-border:      #5b4523;

  --tn-danger:              #ef7570;
  --tn-danger-hover:        #f59894;
  --tn-danger-soft:         #331a1c;
  --tn-danger-border:       #653234;

  --tn-info:                #5cb3cf;
  --tn-info-soft:           #12262e;
  --tn-info-border:         #2b4d5a;

  --tn-neutral-soft:        #212a36;
  --tn-neutral-border:      #333e4d;

  /* --- charts: same six roles, lifted for a dark canvas ---------------- */
  --tn-chart-1:             #5b9bf0;
  --tn-chart-2:             #4cbd88;
  --tn-chart-3:             #e0a94f;
  --tn-chart-4:             #a78bfa;
  --tn-chart-5:             #56b7d1;
  --tn-chart-6:             #ef7570;

  /* Slightly stronger alpha: a 0.16 wash disappears against a dark surface. */
  --tn-chart-1-soft:        rgba(91, 155, 240, 0.22);
  --tn-chart-2-soft:        rgba(76, 189, 136, 0.22);
  --tn-chart-3-soft:        rgba(224, 169, 79, 0.22);
  --tn-chart-4-soft:        rgba(167, 139, 250, 0.22);
  --tn-chart-5-soft:        rgba(86, 183, 209, 0.22);
  --tn-chart-6-soft:        rgba(239, 117, 112, 0.22);

  --tn-chart-grid:          #263140;
  --tn-chart-axis:          #93a0b2;
  --tn-chart-track:         #232d3a;
  --tn-chart-compare:       #62748c;

  /* --- focus --- */
  --tn-focus-ring:          0 0 0 3px rgba(91, 155, 240, 0.28);
  --tn-focus-ring-danger:   0 0 0 3px rgba(239, 117, 112, 0.35);
  --tn-focus-outline-color: #5b9bf0;
  --tn-focus-outline:       2px solid #5b9bf0;

  /* --- sidebar: the night sky, continued ---
     The dark login panel runs #081328 -> #132a4e -> #23477a. The sidebar
     takes a stop from between that mid and that end, so it is literally on
     the login's night-sky ramp rather than a separate navy.

     It is NOT taken deeper than that on purpose. The dark canvas is already
     #0e141c, so a darker sidebar would have nowhere to go and the shell
     would dissolve into the workspace; the separation has to come from the
     sidebar being the LIGHTER, bluer surface. At 1.62:1 against the canvas
     it reads as chrome, marginally better than the 1.61:1 it had before,
     while sitting squarely in the login's family instead of beside it. */
  --tn-side-bg:             #1c396a;
  --tn-side-bg-raised:      #16305c;
  --tn-side-border:         #2a5289;
  --tn-side-text:           #dbe7f7;   /* 9.1:1 on the surface            */
  --tn-side-text-muted:     #a6bcda;   /* 5.9:1                           */
  --tn-side-text-strong:    #ffffff;
  --tn-side-hover-bg:       #24477e;
  --tn-side-active-bg:      #2e5890;   /* white on it: 7.2:1              */
  --tn-side-active-bar:     #78b4f6;   /* the login's dark accent rule    */
  --tn-side-focus-ring:     rgba(120, 180, 246, 0.35);
  --tn-side-logo-bg:        #23477a;   /* the login panel's end stop      */

  /* --- data grid --- */
  --tn-grid-head-bg:          #1a222d;
  --tn-grid-head-text:        #b1bccc;
  --tn-grid-border:           #242e3a;
  --tn-grid-row-hover:        #1b2531;
  --tn-grid-row-alt:          #131a24;
  --tn-grid-row-selected:     #1c2e46;
  --tn-grid-row-selected-bar: #5b9bf0;
  --tn-grid-row-focus:        #223755;

  /* --- form controls: inputs sit slightly below the surface so the
         editable area is obvious without a heavy border --- */
  --tn-input-bg:            #121924;
  --tn-input-bg-disabled:   #1a222d;
  --tn-input-border:        #3c4859;
  --tn-input-border-hover:  #54637a;
  --tn-input-text:          #e7ecf3;
  --tn-input-placeholder:   #7d8b9e;
  --tn-input-placeholder-invalid: #b89a9a;   /* 6.2:1 on the dark danger fill */

  /* --- global chrome: on dark the top bar lifts ABOVE the canvas so it
         cannot disappear into it --- */
  --tn-topbar-bg:           #161d27;
  --tn-topbar-border:       #2f3b4a;

  /* The customer mark is a fixed navy PNG that measures 1.92:1 against this
     top bar, so it is lifted rather than boxed. The Tournate mark is already
     white and needs no treatment here. */
  --tn-logo-tournate:        url("../assets/tournate-logo-white.svg");
  --tn-logo-customer-filter: brightness(2.35) saturate(0.78);
  --tn-topbar-brand-divider: #313d4d;
  --tn-context-bg:          #1c2531;
  --tn-context-bg-hover:    #222d3c;
  --tn-context-border:      #2f3b4a;
  --tn-search-mark-bg:      #1e3a5f;

  --tn-dirty-bg:            #2e2414;
  --tn-dirty-border:        #5b4523;
  --tn-dirty-text:          #e0a94f;

  /* --- Hot Fix on dark ---
     The same amber family, taken up in value rather than inverted: the ink
     lightens so it reads on a dark surface, and the "soft" fills become deep
     tints of the hue instead of pale washes, exactly as every other soft
     token does in this theme. The amber ink measures 8.4:1 on the grid's own
     surface and 6.6:1 on the tinted cell. */
  --tn-hotfix:              #e0a94f;
  --tn-hotfix-strong:       #f0c176;
  --tn-hotfix-soft:         #241d11;
  --tn-hotfix-soft-strong:  #2e2414;
  --tn-hotfix-border:       #7c5f2a;
  --tn-hotfix-ring:         rgba(224, 169, 79, 0.20);
  --tn-hotfix-cell-bg:      #1f1a12;
  --tn-hotfix-new-bg:       #241d11;

  --tn-guide-ring:          rgba(91, 155, 240, 0.42);
  --tn-guide-ring-wide:     rgba(91, 155, 240, 0.16);

  /* --- dialogs on dark ---
     The dialog has to lift OUT of the canvas, so it takes the overlay
     surface and a deeper scrim than light needs — on dark the difference
     between "behind" and "in front" comes from value, not from shadow. */
  --tn-dlg-bg:              var(--tn-surface-overlay);
  --tn-dlg-head-bg:         #232d3b;
  --tn-dlg-foot-bg:         #1b232f;
  --tn-dlg-border:          #33404f;
  --tn-dlg-scrim:           rgba(4, 8, 13, 0.68);
  --tn-dlg-shadow:          0 8px 24px rgba(0, 0, 0, 0.45),
                            0 32px 72px rgba(0, 0, 0, 0.55);

  --tn-dlg-inset-bg:        #141b25;
  --tn-dlg-inset-border:    #2a3441;

  --tn-dlg-tool-shadow:     0 4px 12px rgba(0, 0, 0, 0.42),
                            0 18px 40px rgba(0, 0, 0, 0.52);

  /* --- the page tour on dark ---
     Deeper scrim, because on dark the separation between "described" and
     "quieted" comes from value rather than from shadow; and the lightened
     accent, which is what the whole theme uses for emphasis. */
  --tn-tour-scrim:          rgba(4, 8, 13, 0.60);
  --tn-tour-ring:           #5b9bf0;
  --tn-tour-ring-glow:      rgba(91, 155, 240, 0.34);
  --tn-tour-mark-bg:        var(--tn-surface-overlay);
  --tn-tour-mark-border:    #33404f;
  --tn-tour-mark-shadow:    0 6px 18px rgba(0, 0, 0, 0.48),
                            0 24px 56px rgba(0, 0, 0, 0.56);

  /* The editor canvas stays paper on dark too — see the light block. Its
     chrome is the application's, so only the sheet itself is the exception. */
  --tn-editor-bg:           #f5f7fa;
  --tn-editor-text:         #1b2432;
  --tn-editor-border:       #33404f;
  --tn-editor-bar-bg:       #232d3b;
  --tn-editor-token-bg:     #d7e5f8;
  --tn-editor-token-border: #9dbde6;
  --tn-editor-token-text:   #14477f;

  /* --- login: the NIGHT SKY interpretation ------------------------------
     Not an inversion of the light screen and not the application's dark
     canvas reused. The brand half becomes a midnight sky that still ends on
     a recognisable Tournate blue, and the form half becomes a deep navy
     ground with one restrained ambient lift — no pure black anywhere.

     The whole family is anchored on the brand blue #507eb8: every value
     below is that hue taken down in value, never shifted off-hue toward
     teal or violet. */
  --tn-login-page-bg:       #080e1a;
  --tn-login-panel-bg:      #0a1120;
  --tn-login-form-bg:       #111a2c;
  --tn-login-surface-border: #24334c;
  --tn-login-surface-shadow: 0 1px 2px rgba(0, 0, 0, 0.45),
                             0 18px 44px rgba(2, 8, 20, 0.60);

  /* The sky itself: deep midnight behind the white logo, opening to the
     Tournate family at the far corner where the light sits. The white SVG
     mark measures ~18.6:1 on --tn-login-brand-from. */
  --tn-login-brand-from:    #081328;
  --tn-login-brand-mid:     #132a4e;
  --tn-login-brand-to:      #23477a;
  --tn-login-glow:          rgba(74, 126, 194, 0.22);
  /* The ground, at night-sky strength: a quarter of the light theme's, and
     set on the sky's own deepest tone rather than on black. */
  --tn-login-ground:        rgba(3, 9, 22, 0.50);
  --tn-login-ground-fade:   rgba(3, 9, 22, 0);
  --tn-login-glow-accent:   rgba(99, 198, 214, 0.10);
  --tn-login-accent-rule:   #78b4f6;

  /* --- brand panel atmosphere: NIGHT SKY -------------------------------
     The same three veils, painted as a depth-sorted particle field. Each
     point is one radial-gradient placed by hand: far is many small dim
     ones, near is a few larger brighter ones, and the two washes at the top
     of each list give the field something to sit in so it reads as depth
     rather than as dots on flat navy.

     Placed individually and never tiled — a repeated tile at this density
     is instantly readable as a grid, which is the difference between an
     ambience and a wallpaper. Each point fades to zero through its own hue,
     so none of them draws an edge, and none is a shape: at these radii a
     point IS its glow.

     Colour is restrained on purpose. Most points are the sky's own cool
     white; a handful carry a trace of cyan or violet, which is what stops
     the field looking monochrome without ever reading as festive. The
     left third stays sparse — that is the reading column. */
  --tn-login-veil-far:
    radial-gradient(58% 44% at 78% 22%, rgba(70, 116, 186, 0.16) 0%, rgba(70, 116, 186, 0) 70%),
    radial-gradient(circle 1.5px at 61% 12%, rgba(214, 232, 255, 0.50) 0%, rgba(214, 232, 255, 0) 100%),
    radial-gradient(circle 1px   at 73% 27%, rgba(198, 220, 252, 0.42) 0%, rgba(198, 220, 252, 0) 100%),
    radial-gradient(circle 1.5px at 88% 18%, rgba(226, 240, 255, 0.46) 0%, rgba(226, 240, 255, 0) 100%),
    radial-gradient(circle 1px   at 54% 36%, rgba(186, 212, 248, 0.34) 0%, rgba(186, 212, 248, 0) 100%),
    radial-gradient(circle 1.5px at 93% 41%, rgba(206, 228, 255, 0.44) 0%, rgba(206, 228, 255, 0) 100%),
    radial-gradient(circle 1px   at 67% 53%, rgba(192, 216, 250, 0.36) 0%, rgba(192, 216, 250, 0) 100%),
    radial-gradient(circle 1.5px at 81% 64%, rgba(216, 234, 255, 0.42) 0%, rgba(216, 234, 255, 0) 100%),
    radial-gradient(circle 1px   at 58% 71%, rgba(180, 206, 244, 0.32) 0%, rgba(180, 206, 244, 0) 100%),
    radial-gradient(circle 1.5px at 96% 78%, rgba(210, 230, 255, 0.40) 0%, rgba(210, 230, 255, 0) 100%),
    radial-gradient(circle 1px   at 76% 86%, rgba(196, 220, 252, 0.34) 0%, rgba(196, 220, 252, 0) 100%),
    radial-gradient(circle 1.5px at 47% 84%, rgba(188, 214, 250, 0.30) 0%, rgba(188, 214, 250, 0) 100%),
    radial-gradient(circle 1px   at 33% 19%, rgba(184, 208, 246, 0.34) 0%, rgba(184, 208, 246, 0) 100%),
    radial-gradient(circle 1px   at 22% 62%, rgba(180, 204, 242, 0.30) 0%, rgba(180, 204, 242, 0) 100%),
    radial-gradient(circle 1.5px at 64% 45%, rgba(204, 226, 254, 0.40) 0%, rgba(204, 226, 254, 0) 100%),
    radial-gradient(circle 1px   at 86% 55%, rgba(198, 220, 250, 0.38) 0%, rgba(198, 220, 250, 0) 100%),
    radial-gradient(circle 1.5px at 71% 76%, rgba(212, 232, 255, 0.38) 0%, rgba(212, 232, 255, 0) 100%),
    radial-gradient(circle 1px   at 91% 66%, rgba(190, 214, 248, 0.34) 0%, rgba(190, 214, 248, 0) 100%),
    radial-gradient(circle 1px   at 44% 58%, rgba(186, 210, 246, 0.28) 0%, rgba(186, 210, 246, 0) 100%),
    radial-gradient(circle 1.5px at 52% 26%, rgba(208, 228, 254, 0.36) 0%, rgba(208, 228, 254, 0) 100%);

  --tn-login-veil-mid:
    radial-gradient(46% 38% at 90% 58%, rgba(58, 100, 168, 0.14) 0%, rgba(58, 100, 168, 0) 72%),
    radial-gradient(circle 2px   at 69% 20%, rgba(232, 244, 255, 0.62) 0%, rgba(232, 244, 255, 0) 100%),
    radial-gradient(circle 2.5px at 85% 33%, rgba(180, 226, 246, 0.52) 0%, rgba(180, 226, 246, 0) 100%),
    radial-gradient(circle 2px   at 57% 47%, rgba(224, 238, 255, 0.54) 0%, rgba(224, 238, 255, 0) 100%),
    radial-gradient(circle 2.5px at 94% 24%, rgba(210, 232, 255, 0.56) 0%, rgba(210, 232, 255, 0) 100%),
    radial-gradient(circle 2px   at 74% 69%, rgba(198, 190, 240, 0.46) 0%, rgba(198, 190, 240, 0) 100%),
    radial-gradient(circle 2.5px at 89% 81%, rgba(228, 240, 255, 0.50) 0%, rgba(228, 240, 255, 0) 100%),
    radial-gradient(circle 2px   at 63% 90%, rgba(206, 228, 252, 0.44) 0%, rgba(206, 228, 252, 0) 100%),
    radial-gradient(circle 2px   at 41% 30%, rgba(200, 222, 250, 0.40) 0%, rgba(200, 222, 250, 0) 100%),
    radial-gradient(circle 1.5px at 28% 77%, rgba(194, 216, 246, 0.34) 0%, rgba(194, 216, 246, 0) 100%),
    radial-gradient(circle 2px   at 96% 44%, rgba(186, 228, 248, 0.48) 0%, rgba(186, 228, 248, 0) 100%),
    radial-gradient(circle 2.5px at 79% 12%, rgba(220, 236, 255, 0.46) 0%, rgba(220, 236, 255, 0) 100%),
    radial-gradient(circle 2px   at 50% 66%, rgba(212, 232, 255, 0.42) 0%, rgba(212, 232, 255, 0) 100%);

  --tn-login-veil-near:
    radial-gradient(34% 28% at 76% 40%, rgba(74, 122, 196, 0.13) 0%, rgba(74, 122, 196, 0) 74%),
    radial-gradient(circle 3px   at 80% 29%, rgba(240, 249, 255, 0.72) 0%, rgba(240, 249, 255, 0) 100%),
    radial-gradient(circle 3.5px at 66% 62%, rgba(168, 220, 244, 0.58) 0%, rgba(168, 220, 244, 0) 100%),
    radial-gradient(circle 3px   at 92% 52%, rgba(236, 246, 255, 0.64) 0%, rgba(236, 246, 255, 0) 100%),
    radial-gradient(circle 3.5px at 84% 88%, rgba(204, 196, 244, 0.50) 0%, rgba(204, 196, 244, 0) 100%),
    radial-gradient(circle 3px   at 52% 16%, rgba(232, 244, 255, 0.56) 0%, rgba(232, 244, 255, 0) 100%),
    radial-gradient(circle 3px   at 71% 78%, rgba(238, 247, 255, 0.58) 0%, rgba(238, 247, 255, 0) 100%),
    radial-gradient(circle 2.5px at 58% 36%, rgba(226, 240, 255, 0.50) 0%, rgba(226, 240, 255, 0) 100%);

  /* The anchor lights. Four points only, and the one thing in the field
     bright enough to look at directly — a night sky needs a few stars you
     can actually pick out, or the whole thing reads as dust. Each is a
     small bright core inside a wider soft halo rather than a flat dot,
     which is what makes it a light instead of a mark. They carry their own
     twinkle period, so they vary independently of the three field layers
     underneath and no two of the four ever peak together. */
  --tn-login-veil-accent:
    radial-gradient(circle 5px at 83% 26%,
      rgba(255, 255, 255, 0.95) 0%, rgba(214, 235, 255, 0.40) 26%, rgba(200, 226, 255, 0) 100%),
    radial-gradient(circle 4.5px at 68% 71%,
      rgba(240, 250, 255, 0.88) 0%, rgba(176, 224, 248, 0.36) 28%, rgba(176, 224, 248, 0) 100%),
    radial-gradient(circle 4px at 94% 58%,
      rgba(255, 255, 255, 0.86) 0%, rgba(210, 232, 255, 0.34) 28%, rgba(210, 232, 255, 0) 100%),
    radial-gradient(circle 4.5px at 56% 41%,
      rgba(246, 244, 255, 0.82) 0%, rgba(206, 198, 246, 0.32) 28%, rgba(206, 198, 246, 0) 100%);

  --tn-login-shade:         rgba(2, 7, 18, 0.62);
  /* Starlight rather than white: the arcs pick up the sky's own hue. */
  --tn-login-ring:          rgba(173, 205, 245, 0.07);
  --tn-login-ring-strong:   rgba(173, 205, 245, 0.13);
  --tn-login-brand-text:    rgba(255, 255, 255, 0.96);
  --tn-login-brand-muted:   rgba(255, 255, 255, 0.80);
  --tn-login-brand-faint:   rgba(255, 255, 255, 0.64);

  /* --- integration logo tiles -------------------------------------------
     The tile still has to be the light one. Nine of the twenty logos are
     black or deep navy and no amount of dark-mode styling makes those
     readable on a night panel — a translucent smoked-glass card would
     simply delete them. What changes is the temperature and the level: a
     soft dove tone at nine tenths reads as a lit surface rather than as a
     light source, where paper white would be a hole punched in the sky.

     It composites to about #ccd6e5, which costs roughly a third of the
     light theme's contrast and still leaves the nine deep marks at 6.6:1
     or better. The shadow is much deeper than Light's, because in here it
     is the shadow rather than the wash that tells you the tile is a card. */
  --tn-login-integration-bg:      rgba(224, 233, 246, 0.90);
  --tn-login-integration-border:  rgba(255, 255, 255, 0.26);
  --tn-login-integration-shadow:  0 1px 2px rgba(0, 0, 0, 0.44),
                                  0 12px 28px -10px rgba(0, 0, 0, 0.62);

  --tn-login-ornament:      rgba(255, 255, 255, 0.15);
  --tn-login-ornament-soft: rgba(255, 255, 255, 0.09);
  --tn-login-route:         rgba(255, 255, 255, 0.20);

  /* --- login: form side, controls and typography ------------------------
     The dark form half is DESIGNED, not recoloured: the ground is the
     darkest layer, the card lifts out of it, and the inputs sit back down
     below the card so the editable area reads without a heavy border. */

  /* Two very wide, very low ambient lifts — one from the top-right corner
     (the sky's light bleeding across the seam) and one from the bottom-left.
     Both fade through their own hue, so there is no grey rim and no
     perceptible circumference. */
  --tn-login-ambient-a:     rgba(64, 116, 190, 0.26);
  --tn-login-ambient-b:     rgba(80, 126, 184, 0.15);
  --tn-login-ambient-fade:  rgba(64, 116, 190, 0);

  --tn-login-divider:        #1e2c42;
  --tn-login-text:           #e9eff8;
  --tn-login-text-secondary: #b4c2d7;
  --tn-login-text-muted:     #8d9db6;   /* 6.4:1 on the card             */

  --tn-login-input-bg:           #0c1424;
  --tn-login-input-border:       #2a3b58;
  --tn-login-input-border-hover: #3a4f74;
  --tn-login-input-text:         #eaf0f9;
  --tn-login-input-placeholder:  #7b8ba6;   /* 5.4:1 on the input        */
  --tn-login-input-icon:         #8296b4;

  /* Preference controls. The selected segment is a deep Tournate tint that
     lifts off the track by value, not by a glowing border. */
  --tn-login-control-bg:              #0d1524;
  --tn-login-control-hover-bg:        #16223a;
  --tn-login-control-border:          #26364f;
  --tn-login-control-text:            #a8b7ce;   /* 9.1:1 on the track   */
  --tn-login-control-selected-bg:     #1b3053;
  --tn-login-control-selected-border: #35578a;
  --tn-login-control-selected-text:   #d4e4fb;   /* 10.2:1 on selection  */
  --tn-login-control-selected-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);

  /* --- misc --- */
  --tn-scrim:               rgba(4, 8, 13, 0.62);
  --tn-switch-track:        #3c4859;
  --tn-switch-knob:         #e7ecf3;
  --tn-skeleton-a:          #1a222d;
  --tn-skeleton-b:          #253040;

  /* In dark the veil is the dark surface at the same alpha, for the same
     reason: it must read as "this surface, suspended", not as a shadow
     falling across it. */
  --tn-veil:                rgba(22, 29, 39, 0.72);
  --tn-veil-strong:         rgba(22, 29, 39, 0.90);

  --tn-drop-border:         var(--tn-border-strong);
  --tn-drop-border-over:    var(--tn-accent);
  --tn-drop-bg:             var(--tn-surface-sunken);
  --tn-drop-bg-over:        var(--tn-accent-soft);

  --tn-progress-track:      var(--tn-chart-track);
  --tn-progress-fill:       var(--tn-accent);

  --tn-scrollbar-thumb:       #384453;
  --tn-scrollbar-thumb-hover: #4a5768;

  /* --- elevation: darker and wider, since a light shadow is invisible --- */
  --tn-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.30);
  --tn-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.34), 0 2px 8px rgba(0, 0, 0, 0.30);
  --tn-shadow-md: 0 2px 6px rgba(0, 0, 0, 0.40), 0 12px 28px rgba(0, 0, 0, 0.46);
  --tn-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.45), 0 24px 56px rgba(0, 0, 0, 0.55);
}

/* Theme changes are instant by default. A short colour transition on the
   large planes makes the switch feel deliberate rather than jarring, and is
   suppressed for users who ask for reduced motion. */
.tn-body,
.app-shell,
.topbar,
.sidebar,
.panel,
.workspace {
  transition: background-color var(--tn-dur-base) var(--tn-ease),
              border-color var(--tn-dur-base) var(--tn-ease),
              color var(--tn-dur-base) var(--tn-ease);
}

@media (prefers-reduced-motion: reduce) {
  .tn-body,
  .app-shell,
  .topbar,
  .sidebar,
  .panel,
  .workspace {
    transition: none;
  }
}

/* ==========================================================================
   PAPER — the printed report's palette.

   Declared once on :root rather than twice in the theme blocks, because it
   is deliberately NOT themed. Paper is white whichever theme the operator
   is working in, and a dark-theme report would print as a sheet of ink;
   these tokens are read only by css/print.css inside @media print, so
   nothing on screen can reach them and no theme can override them.

   They live here rather than in print.css for the ordinary reason: this is
   the file colour lives in.
   ========================================================================== */
:root {
  --tn-paper:        #ffffff;
  --tn-paper-ink:    #14202f;   /* body text on paper                       */
  --tn-paper-muted:  #5a6577;   /* labels, captions, page furniture         */
  --tn-paper-rule:   #c8d1dd;   /* table rules                              */
  --tn-paper-edge:   #b9c2cf;   /* the heavier rule under the report head   */
  --tn-paper-band:   #eef2f7;   /* table header and totals band             */
}
