/* ============================================================
   THE ROOM, EVERYWHERE

   The landing page has a television with a handle on it. Pull the
   handle and that page's daylight drains away. This file is what makes
   the rest of the site agree: walk from the landing page into a case
   study or into About with the lights off, and you arrive in the same
   dark room rather than being flashbanged by a page that never got the
   message.

   ONE VALUE, STILL
   ----------------
   Everything is driven by --lit, exactly as before: 1 is daylight, 0
   is the room dark. What changed is only WHERE it lives and how long
   it survives.

     was:  --lit on .home-page, alive for one page view
     now:  --lit on :root, persisted, read back before first paint

   It has to sit on :root rather than on body, and that is not
   arbitrary. color-mix() resolves against the --lit that is in scope
   AT THE ELEMENT WHERE THE TOKEN IS DECLARED. Declare the tokens on
   :root and set --lit on body and the tokens would keep computing from
   :root's default of 1 forever, silently, while body's value inherited
   past them to nothing that reads it. Same element for both, or the
   whole system quietly does nothing.

   THE COST THIS FILE DELIBERATELY TAKES ON
   ----------------------------------------
   room-light.js used to carry a comment justifying the opposite
   decision: not persisted, not seeded, "no storage, no inline head
   script and therefore no flash of the wrong state to defend." That
   was the right call when the room was one page. It stops being right
   the moment leaving the page is supposed to preserve the state, so
   the two costs are now paid properly rather than avoided:

     storage      one key, room-lit, written only on a committed
                  toggle — see room-light.js
     head script  an inline boot snippet in every participating page,
                  which MUST stay inline and MUST stay in <head>. An
                  external file is a network round trip, and a round
                  trip is a flash of the wrong room.

   THE CAVE
   --------
   The Cave used to opt out: it was the room with the lights off, and
   this file's night palette was copied from it. It opens lit now, and
   loads this file like every other page, so the room's light follows
   you in and out of it. It has no switch of its own; with the light
   off, its objects are lit by a lamp (cave/lamp.js) rather than by
   the room.
   ============================================================ */

/* Registered so it is a real number rather than a token string, which
   is what lets it drive calc() inside color-mix() and filters without
   every consumer re-parsing it. */
@property --lit {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

:root {
  --lit: 1;

  /* The night end of every room value is the CAVE's palette, verbatim.
     Not a coincidence and not laziness: the Cave is the room with the
     lights off, so when this room's lights go off the two should be
     the same room. Sharing the values is what makes that true rather
     than merely claimed. */
  --day-bg: #d9d6d0;        --night-bg: #14100c;
  --day-bg-deep: #cbc8c1;   --night-bg-deep: #0f0c08;
  --day-ink: #181512;       --night-ink: #f2e7d8;
  --day-ink-muted: #524c42; --night-ink-muted: #bdae9b;
  --day-ink-faint: #625c51; --night-ink-faint: #a89a86;

  /* Ink crosses over on a STEEPER curve than the surface, and that is
     a legibility fix rather than a flourish. Dark ink on a light
     ground becoming light ink on a dark ground has to pass through a
     point where both are mid-grey and nothing is readable. Running the
     ink's crossover fast and late — held at day until the surface is
     already well down, then switched over a narrow band — keeps the
     unreadable window as short as the drag can make it.

     smoothstep(0.34, 0.60) expressed in clamp/calc: 0 below 0.34,
     1 above 0.60, and a linear ramp between. */
  --ink-lit: clamp(0, calc((var(--lit) - 0.34) / 0.26), 1);

  /* oklab, not sRGB: interpolating warm near-black to warm off-white
     through sRGB passes through a dead grey and loses the warmth that
     makes this room feel like a room. */
  --bg:        color-mix(in oklab, var(--day-bg)        calc(var(--lit) * 100%), var(--night-bg));
  --bg-deep:   color-mix(in oklab, var(--day-bg-deep)   calc(var(--lit) * 100%), var(--night-bg-deep));
  --ink:       color-mix(in oklab, var(--day-ink)       calc(var(--ink-lit) * 100%), var(--night-ink));
  --ink-muted: color-mix(in oklab, var(--day-ink-muted) calc(var(--ink-lit) * 100%), var(--night-ink-muted));
  --ink-faint: color-mix(in oklab, var(--day-ink-faint) calc(var(--ink-lit) * 100%), var(--night-ink-faint));

  /* ---- the case-study vocabulary ----
     The case studies were built against a different set of names than
     the landing page (docs/case-study-standard.md §10 is the contract:
     --text, --muted, --panel, --panel-border, --panel-shadow,
     --stroke). Rather than rename across six files and risk breaking
     five working pages, the two vocabularies are aliased here: --text
     resolves to the same computed colour as --ink, and so on down.
     One system, two names for it, no page edited to satisfy a
     rename. */
  --text:  var(--ink);
  --muted: var(--ink-muted);
  --panel:        color-mix(in oklab, #e4e0d8 calc(var(--lit) * 100%), #1b1611);
  --panel-border: color-mix(in oklab, #d5d0c6 calc(var(--lit) * 100%), #2b241c);
  --stroke:       color-mix(in oklab, #bdb7ab calc(var(--lit) * 100%), #383026);
  /* the panel's lift has to deepen as the room does, or a raised card
     at night reads as flat paper with a grey smudge under it */
  --panel-shadow: 0 12px 16px rgba(0, 0, 0, calc(0.05 + 0.25 * (1 - var(--lit))));

  /* The case-study hero "stage": a soft pool of light the phone stands
     in, which fades up out of nothing and resolves down into --bg. It
     is deliberately a hair LIFTED off the page ground at both ends of
     the range rather than matching it, because the whole point of the
     shape is that the product is standing in a lit spot. Its own
     gradient stops need alpha, which color-mix() cannot append to a
     result — so the tint is published opaque here and each stop dilutes
     it with `color-mix(in oklab, transparent, var(--stage-tint) N%)`. */
  --stage-tint: color-mix(in oklab, #dcd8d1 calc(var(--lit) * 100%), #1e1710);

  /* A card that lifts off the page with a translucent white veil
     rather than a solid fill. The same 35% white that reads as a
     raised card in daylight reads as a BRIGHT SLAB at night — light
     text on a light card, which is how this one got caught: a hex-only
     scan misses rgba() entirely, and only a real contrast measurement
     on the rendered page turned it up (1.22:1). Dark rooms lift a
     surface with far less white than lit rooms do, so the alpha
     collapses as the lights go down. color-mix interpolates alpha as
     well as colour, so one token covers both ends. */
  --card-veil: color-mix(in oklab,
    rgba(255, 255, 255, 0.35) calc(var(--lit) * 100%),
    rgba(255, 255, 255, 0.055));

  /* the page's own floor, so an overscroll bounce or a short page does
     not reveal a white strip behind the dark room */
  background: var(--bg);
}

/* ---------- the chrome is in the room too ----------

   nav.css and footer.css are shared by eight pages and hardcode their
   surfaces, so left alone they stay in daylight while the room goes
   dark — which is not a small blemish, it is two hard light bands
   across the top and bottom of the picture. Overridden here rather
   than edited there, so neither shared file has to grow a theme
   dependency, and so a page that does not load this file is entirely
   unaffected.

   These used to be scoped to .home-page. Un-scoping them is most of
   what makes the rest of the site participate at all. */

/* nav.css and footer.css draw from tokens now, so the night values are
   the same tokens redefined here — on :root, beside --lit, for the
   reason the top of this file gives: color-mix resolves --lit where the
   token is declared. */
:root {
  --nav-veil: color-mix(in oklab,
    rgba(217, 214, 208, 0.4) calc(var(--lit) * 100%), rgba(20, 16, 12, 0.42));
  --nav-veil-solid: var(--bg);
  --nav-pill: color-mix(in oklab, #dedad4 calc(var(--lit) * 100%), #1f1913);
  --nav-pill-edge: color-mix(in oklab, #c6c2bb calc(var(--lit) * 100%), #362c22);
  --nav-pill-shadow: 0 8px 16px rgba(24, 21, 18, calc(0.11 + 0.23 * (1 - var(--lit))));
  --nav-ink: color-mix(in oklab, #5f594f calc(var(--ink-lit) * 100%), #b3a693);
  --nav-active: color-mix(in oklab, #f3ede4 calc(var(--lit) * 100%), #2e251c);
  --nav-active-edge: color-mix(in oklab, #ccc7be calc(var(--lit) * 100%), #45392c);
  --nav-active-ink: color-mix(in oklab, #181512 calc(var(--ink-lit) * 100%), #f2e7d8);

  /* The footer's floor follows the room down. Its gradient already
     starts from var(--bg), so only the three stops below it need a
     night value, and they resolve so the page still ends on one
     continuous surface with no seam. */
  --footer-floor-1: color-mix(in oklab, #d3cfc8 calc(var(--lit) * 100%), #120e0a);
  --footer-floor-2: color-mix(in oklab, #cbc7bf calc(var(--lit) * 100%), #0f0c08);
  --footer-floor-3: color-mix(in oklab, #c6c2b9 calc(var(--lit) * 100%), #0a0806);
}
.site-footer__name { color: var(--ink); }
.site-footer__role,
.site-footer__base { color: var(--ink-muted); }
.site-footer__email { color: var(--ink); }
.site-footer__social-link { color: var(--ink-muted); }
.site-footer__social-link:hover { color: var(--ink); }

/* The avatar is a printed portrait, not a UI element: it dims with the
   objects rather than inverting with the type. */
.site-footer__avatar {
  filter: brightness(calc(0.42 + 0.58 * var(--lit)));
}

/* ---------- artifacts are lit, never recoloured ----------

   The same law the landing page's cassettes follow, applied to what
   the other pages are actually made of: phone mockups, product
   screenshots, device frames, a chat window, a cassette label.

   These are ARTIFACTS — things being shown, like a photograph pinned
   to a wall. A screenshot of the DANA wallet does not become a
   different screenshot when you turn the lights off, so none of the
   colour inside one is allowed to invert. What it does do is receive
   less light, and warmer light, because a room lit by one tungsten
   source is warmer than a room lit by daylight. That is exactly what
   this filter says, and it is the entire treatment.

   Kept mild on purpose. These carry real content — UI copy, labels,
   numbers a reader is meant to read — so the brightness floor is high
   enough that nothing inside a mockup becomes unreadable at night.
   The landing page learned this the expensive way: dimming its
   cassette shells to 0.30 put their printed labels at 2.2:1.

   Targeting `img` rather than a list of container classes is
   deliberate. Every screenshot and mockup on these pages is an <img>
   inside some wrapper — .ob-img-panel, .evolution-gallery,
   .intro-phone, .initiative-media and a dozen more, a list that grows
   every time a section is added and would be stale within a week.
   The images themselves are the stable thing. Filtering the wrapper
   instead would also double-apply to the image inside it, since a
   filter rasterises the whole subtree and a child cannot opt out.

   The scope list is wrapped in :where() so it contributes NO
   specificity. That is load-bearing: the footer lives inside <body>,
   so a body-class scope would otherwise match .site-footer__avatar
   too, and `.dana-wallet-v3-page img` (0,1,1) would outrank
   `.site-footer__avatar` (0,1,0) and silently steal the avatar's own
   treatment. At :where()'s zero specificity this rule scores 0,0,1
   and the avatar keeps its rule. */
:where(
  .about-page,
  .about-letter,
  .dana-wallet-v3-page,
  .weather-but-fun-page,
  .foreign-account-page,
  .main-gate-page,
  .onboarding-page
) img {
  filter:
    brightness(calc(0.88 + 0.12 * var(--lit)))
    saturate(calc(0.94 + 0.06 * var(--lit)))
    sepia(calc(0.16 * (1 - var(--lit))));
}

/* ---------- ink pinned to the paper it is printed on ----------

   The subtle half of the same law, and the one that actually drew
   blood. Some artifacts are not images — they are real elements with
   a FIXED light surface: the cassette liner note (--paper, #f7efdf),
   a polaroid's card stock, a chat mockup's input field. Their
   backgrounds correctly do not follow the room, because printed card
   stock does not change colour when you switch the lights off.

   But their TEXT was reading var(--ink), which does follow the room.
   So at night the ink inverted to near-white and went on sitting on
   cream paper — measured at 1.07:1 on the About page, i.e. gone. It
   is the exact inverse of the mistake this whole system is built to
   avoid: the artifact stayed put and the ink walked off it.

   Re-pinning the tokens on the artifact's own root fixes the entire
   subtree in one declaration, because custom properties inherit. Note
   that --text and --muted have to be re-pinned EXPLICITLY rather than
   left to follow --ink: `--text: var(--ink)` up on :root already
   resolved against :root's --ink, and that computed value is what
   inherits down — redeclaring --ink here would not reach it. */
.cass-panel,
.tl-polaroid,
.pol,
.about-hd__circle,
.chat__input,
.about-page .chat-input {
  --ink:       var(--day-ink);
  --ink-muted: var(--day-ink-muted);
  --ink-faint: var(--day-ink-faint);
  --text:      var(--day-ink);
  --muted:     var(--day-ink-muted);
}

/* ---------- minimal dot-grid background (pratham-style) ----------
   A single fixed layer of 1px dots at ~16-18px pitch, softly feathered
   at the viewport edge so it reads as texture rather than graph paper. Mirrors
   pratham_portfoilio/components/layout/dot-field.tsx:
     bg-[radial-gradient(var(--dot)_1px,transparent_0)]
     bg-[length:10px_10px] + mask-x/y fade

   No DOM needed: html::before paints behind the page, above the solid
   --bg but below the content (.wrap is z-index:1) and below the
   vignette/grain overlays (z-index 1999+). The dot colour tracks --ink
   so it inverts with --lit automatically (dark dots on light ground,
   light dots on dark ground) at a single low alpha — the same
   color-mix trick the file already uses everywhere else. */
html::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  --dot: color-mix(in oklab, var(--ink) 14%, transparent);
  background-image: radial-gradient(circle, var(--dot) 1.05px, transparent 1.1px);
  background-size: 16px 16px;
  background-position: 0 0;
  /* Pratham fades ~5% from the sides and ~10% from top/bottom
   (mask-x-from-95% / mask-y-from-90%). A generous ellipse gives the
   whole viewport a consistent field while easing only at its edges. */
  -webkit-mask-image: radial-gradient(ellipse 128% 96% at 50% 45%, black 64%, transparent 100%);
          mask-image: radial-gradient(ellipse 128% 96% at 50% 45%, black 64%, transparent 100%);
}

@media (prefers-reduced-motion: no-preference) {
  /* keep the rule present for future motion if needed; dots are static */
}
