/* =============================================================
   NIVE — theme layer

   Deliberately its OWN file, not an addition to nive.css. nive.css
   carries about fifty real rules — headers, buttons, cards — and
   three pages (profile, report, viewer) were built without it. Adding
   it to them to reach the tokens restyled those pages on the spot.
   This file contains no layout and no components: only token values
   and the switch. It is safe to link anywhere.

   HOW DARK STAYS UNTOUCHED
   Nothing here applies until the theme is switched. Every rule is
   scoped to html[data-theme="light"], whose specificity beats the
   :root blocks each page defines, so the dark theme renders exactly
   as it did before this file existed — verified pixel by pixel.
   ============================================================= */

/* -------------------------------------------------------------
   LIGHT PALETTE

   Not an inversion. Flipping white-on-black to black-on-white gives
   the generic grey every SaaS product ships, and NIVE's argument is
   that it is not one of those. This is the studio's interiors
   language instead — ivory ground, taupe structure, walnut ink,
   bronze accent: the paper side of the same brand.
   ------------------------------------------------------------- */
/* -------------------------------------------------------------
   SEMANTIC TOKENS

   The pages were written with literal colours — color:#fff about
   ninety times, background:#000 about thirty. Literals cannot
   respond to a theme, which is why the first light build had white
   text on ivory and invisible buttons.

   These four names replace them. Their DARK values are byte-identical
   to the literals they stand in for, so introducing them changes
   nothing until the theme flips — proven by pixel comparison.

     --ink        primary text        #fff on dark
     --surface    page/element ground #000 on dark
     --invert-bg  the "solid" button, which is deliberately the
     --invert-fg  opposite of the page it sits on
   ------------------------------------------------------------- */
:root {
  --ink:       #fff;
  --surface:   #000;
  --invert-bg: #fff;
  --invert-fg: #0A0A0A;

  /* The same two colours as raw channels, so the hundreds of existing
     rgba(255,255,255,.42)-style rules become theme-aware by swapping
     the channels and keeping their own alpha. Nothing else reaches
     them: they are literals inside shorthand properties, not tokens. */
  --ink-rgb:     255, 255, 255;
  --surface-rgb: 0, 0, 0;

  /* Alphas that appear as literals in the pages and sit between the
     --wNN steps. They exist so those rules can be tokenised without
     being rounded onto a neighbouring step — rounding .52 down to
     --w40 dimmed a line of dark-theme text, which the pixel check
     caught. Dark values are exact; light values are retuned. */
  --w52: rgba(255, 255, 255, 0.52);
  --w48: rgba(255, 255, 255, 0.48);
  --w45: rgba(255, 255, 255, 0.45);

  /* What shows behind the sign-in hero until a render is dropped at
     assets/hero.jpg. The scrim sits over it at 70%, so if this stays
     dark under a light scrim the result is mud, not ivory. */
  --hero-bg: #0E120D;
}

html[data-theme="light"] {
  /* Bronze, not gold. The dark theme's #C6A15B is tuned to glow
     against near-black; on ivory it goes muddy and fails contrast. */
  /* Darkened from #8A6A2F, which measured 4.45:1 on ivory for the
     wordmark and missed AA by a hair. Bronze, not brown — it still
     reads as the gold's daylight twin. */
  --gold:      #7A5A22;
  --gold-glow: rgba(122, 90, 34, 0.18);

  /* The --wNN scale means "ink at NN%". Names stay so every existing
     rule keeps working; only the ink changes — white to a warm
     near-black that reads as walnut, never as flat black on paper. */
  /* These carry more weight than their dark-theme counterparts on
     purpose. White at 40% on near-black is comfortably legible;
     black at 40% on ivory is not — it measured 3.47:1, under AA.
     The scale is tuned for the surface it sits on, not copied. */
  --w70: rgba(38, 32, 26, 0.92);
  --w58: rgba(38, 32, 26, 0.78);
  --w40: rgba(38, 32, 26, 0.68);
  --w30: rgba(38, 32, 26, 0.56);
  --w28: rgba(38, 32, 26, 0.22);
  --w15: rgba(38, 32, 26, 0.14);
  --w10: rgba(38, 32, 26, 0.11);
  --w05: rgba(38, 32, 26, 0.055);

  --bg-dark:  #F4F1EA;   /* ivory — plain white glares under studio lights */
  --card:     #FBF9F5;
  --card-bg:  #FBF9F5;
  --bar:      #FBF9F5;
  /* NOT --hero. On signin.html that token holds url('assets/hero.jpg')
     — an image, not a colour. Overriding it with a hex made
     background-image invalid and dropped the hero layer entirely. A
     token's NAME does not tell you its type. */

  /* Walnut ink on ivory. Never #000 on #FFF — that is the glare the
     dark theme exists to avoid, reintroduced on paper. */
  --ink:       #26201A;
  --surface:   #F4F1EA;

  /* The solid button inverts against its page, so on ivory it goes
     dark. Keeping it white would make it vanish. */
  --invert-bg: #26201A;
  --invert-fg: #FBF9F5;

  --ink-rgb:     38, 32, 26;
  --surface-rgb: 244, 241, 234;

  --w52: rgba(38, 32, 26, 0.74);
  --w48: rgba(38, 32, 26, 0.71);
  --w45: rgba(38, 32, 26, 0.68);
  --hero-bg: #E6E1D5;

  color-scheme: light;
}

/* Renders and photography are graded for a dark surround and read hot
   on ivory. Barely a touch — enough to settle them, not enough to
   misrepresent the work. */
html[data-theme="light"] img:not([src$=".svg"]) { filter: saturate(.96) brightness(.985); }

/* -------------------------------------------------------------
   THE SWITCH
   Fixed chrome, never part of a page's own layout, so it cannot
   shift anything on any page it appears on.
   ------------------------------------------------------------- */
.nive-theme-toggle {
  position: fixed; right: 18px; bottom: 18px; z-index: 9998;
  width: 58px; height: 30px; padding: 0; border: 0;
  border-radius: 100px; cursor: pointer;
  background: rgba(255,255,255,.06);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.16);
  transition: background .35s ease, box-shadow .35s ease;
  -webkit-tap-highlight-color: transparent;
}
html[data-theme="light"] .nive-theme-toggle {
  background: rgba(38,32,26,.06);
  box-shadow: inset 0 0 0 1px rgba(38,32,26,.18);
}
.nive-theme-toggle:hover     { box-shadow: inset 0 0 0 1px var(--gold, #C6A15B); }
.nive-theme-toggle:focus-visible { outline: 2px solid var(--gold, #C6A15B); outline-offset: 3px; }

/* The travelling knob carries both icons and cross-fades them as it
   slides, so the control shows the state rather than labelling it. */
.nive-theme-toggle .knob {
  position: absolute; top: 3px; left: 3px;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--gold, #C6A15B);
  display: grid; place-items: center;
  transition: transform .4s cubic-bezier(.34,1.3,.42,1), background .35s ease;
}
html[data-theme="light"] .nive-theme-toggle .knob { transform: translateX(28px); }

.nive-theme-toggle .knob svg {
  position: absolute; width: 13px; height: 13px;
  transition: opacity .26s ease, transform .4s ease;
}
.nive-theme-toggle .i-moon { opacity: 1; transform: rotate(0) scale(1); }
.nive-theme-toggle .i-sun  { opacity: 0; transform: rotate(-90deg) scale(.4); }
html[data-theme="light"] .nive-theme-toggle .i-moon { opacity: 0; transform: rotate(90deg) scale(.4); }
html[data-theme="light"] .nive-theme-toggle .i-sun  { opacity: 1; transform: rotate(0) scale(1); }

/* A theme change repaints everything. Without this it reads as a
   flicker; with it, as a dissolve. Applied only for the moment of the
   switch, so it never slows an ordinary page load. */
html.nive-theming, html.nive-theming * {
  transition: background-color .3s ease, color .3s ease, border-color .3s ease, fill .3s ease !important;
}

@media (prefers-reduced-motion: reduce) {
  .nive-theme-toggle, .nive-theme-toggle .knob, .nive-theme-toggle .knob svg,
  html.nive-theming, html.nive-theming * { transition: none !important; }
}
@media print { .nive-theme-toggle { display: none !important; } }
