/* ═══════════════════════════════════════════════════════════════
   ORIGINAL SOURCE, www.tejj.in
   © 2025 Ravi Tej Sireddy ("Tejj"). All rights reserved.
   Canary: TEJJ-ORIG-9F4E8B2A-2026-RVT-DO-NOT-COPY
   ═══════════════════════════════════════════════════════════════

   SIGNAL THEME, dual palette
   ---------------------------------------------------------------
   Default (no data-theme attribute) = Signal, cool blue on ink.
   html[data-theme="warm"]           = the original coral palette.

   Both selectors are (0,1,1) specificity, so they outrank each
   page's inline :root (0,1,0) without those blocks being edited.
   The two selectors are mutually exclusive, so source order here
   carries no meaning.

   Pages reference colour through tokens only. The -rgb tokens hold
   bare triplets so existing alpha values survive untouched, e.g.
   rgba(var(--cream-rgb),.42).
   ─────────────────────────────────────────────────────────────── */

/* ── SIGNAL, default ────────────────────────────────────────── */
html:not([data-theme="warm"]){
  --cream:#eef2f7;      --cream-rgb:238,242,247;
  --cream2:#e7edf6;     --cream2-rgb:231,237,246;
  --crd:#f5f7fb;
  --red:#3763e8;        --red-rgb:55,99,232;
  --redx:#3763e8;       --redx-rgb:55,99,232;
  --redp:#7591ee;       --redp-rgb:117,145,238;
  --gold:#3ad4ff;       --gold-rgb:58,212,255;
  --redd:#1e3fa8;       /* deep accent, emissive glow in the 3D scene */
  --creamd:#a8bcd4;     /* dimmed cream, emissive in the 3D scene */
  --pol-meta:#79808c;   /* caption ink on the cream polaroid cards */
  --pin-hi:#5b8bff;     /* push-pin head on the polaroids */
  --pin-lo:#1d3fb6;
  /* Side banner art, carried over from theme-blue-dusk. The source coral sits
     at hue 12deg; +218 lands it on a dusk blue, and the chroma is pulled back
     so the drawings sit behind the accent rather than competing with it. */
  --art-hue:218deg;
  --art-trim:saturate(.58);
  --art-trim-hover:saturate(.79) brightness(1.1);
}

/* ── WARM, the original coral palette ───────────────────────── */
html[data-theme="warm"]{
  --cream:#f2e4cc;      --cream-rgb:242,228,204;
  --cream2:#f6ecda;     --cream2-rgb:246,236,218;
  --crd:#f5ece3;
  --red:#c96451;        --red-rgb:201,100,81;
  --redx:#e35342;       --redx-rgb:227,83,66;
  --redp:#f86c69;       --redp-rgb:248,108,105;
  --gold:#edbe24;       --gold-rgb:237,190,36;
  --redd:#aa3322;
  --creamd:#d4c8a8;
  --pol-meta:#8a7a66;
  --pin-hi:#ff5e4a;
  --pin-lo:#b62b1d;
  --art-hue:0deg;
  --art-trim:saturate(1);
  --art-trim-hover:saturate(1);
}

/* ── READABILITY FLOOR ────────────────────────────────────────
   Informational labels use these roles. Decorative type, counters, grids and
   image overlays keep their page-owned lower contrast. */
html{
  --tj-text-secondary:rgba(var(--cream-rgb),.72);
  --tj-text-muted:rgba(var(--cream-rgb),.62);
  --tj-text-caption:rgba(var(--cream-rgb),.68);
}
html .na,
html .na-contact{
  font-size:9px;
  letter-spacing:.18em;
  opacity:.76;
}
html .mob-close{
  font-size:11px;
  color:var(--tj-text-secondary);
}
html .mi{
  font-size:11px;
  letter-spacing:.16em;
  color:var(--tj-text-muted);
}
html .foot-cs-val{
  font-size:12px;
  color:var(--tj-text-secondary);
}

/* Homepage labels and controls that carry meaning, rather than atmosphere. */
html .ssc-rail,
html .ssc-tab,
html .ssc-t-num,
html .ssc-card-num,
html .h-eyebrow,
html .illo-status,
html .illo-sub,
html .illo-loc,
html .proj-all,
html .pj-cta,
html .book-stamp-sub,
html .book-voices-lbl,
html .pod-album-hint,
html .pod-cover-ep,
html .talks-hint,
html .talks-scatter,
html .pod-profile-handle,
html .pod-vc-role,
html .pod-eq-time,
html .connect-lbl{
  font-size:11px;
  color:var(--tj-text-secondary);
}
html .ssc-t-num{color:var(--tj-text-muted)}
html .ssc-title:hover .ssc-t-num{color:rgba(var(--cream-rgb),.82)}
html .ssc-t-chip{
  font-size:10px!important;
  letter-spacing:.16em;
  color:var(--tj-text-muted);
  border-color:rgba(var(--cream-rgb),.14);
}
html .ssc-card-num{color:rgba(255,255,255,.68)}
html .ssc-rail{color:var(--tj-text-secondary)}
html .ssc-tab{color:var(--tj-text-secondary);border-color:rgba(var(--cream-rgb),.14)}
html .illo-status{border-color:rgba(var(--redx-rgb),.30)}
html .illo-blbl{
  font-size:12px;
  font-weight:500;
  letter-spacing:.16em;
  color:var(--tj-text-secondary);
}
html .illo-blbl::before{width:18px;background:rgba(var(--cream-rgb),.46)}
html .pod-stat-label{font-size:12px;color:var(--tj-text-secondary)}

/* Resources: navigation aids, card descriptions and attribution metadata. */
html .sec-lbl,
html .hero-tag{
  font-size:11px;
  letter-spacing:.18em;
  color:var(--redp);
  opacity:1;
}
html .hero-sub{
  font-size:16px;
  color:var(--tj-text-secondary);
  /* The WebGL artifact sits ~7px off this column at 1440, so the copy needs its
     own gutter rather than running to the edge of its box. */
  padding-right:clamp(14px,2.2vw,40px);
  /* Stops the last line ending on a lone word. */
  text-wrap:pretty;
}
/* Below 780 the artifact stacks instead of sitting alongside, so the gutter goes
   and the page's own reading size applies. */
@media(max-width:780px){
  html .hero-sub{font-size:18px;line-height:1.55;padding-right:0}
}
html .hero-note p{font-size:14px;color:var(--tj-text-secondary)}
html .hero-cred{
  font-size:11px;
  letter-spacing:.1em;
  color:var(--tj-text-secondary);
}
html .htu-tag{font-size:12px;letter-spacing:.14em;color:var(--tj-text-secondary)}
/* pretty keeps these card paragraphs off a one-word last line. */
html .htu-desc{font-size:15px;line-height:1.65;color:var(--tj-text-caption);text-wrap:pretty}
html .mq-note,
html .mq-jump{
  font-size:11px;
  letter-spacing:.1em;
  color:var(--tj-text-secondary);
}
html .mq-jump b{font-size:11px}
html .mq-item{font-size:12px;color:var(--tj-text-caption)}
html .mq-kind{font-size:10px;color:var(--redp);opacity:1}
html .pod-row .pod-desc{font-size:15px;color:var(--tj-text-caption)}
html .pod-meta{font-size:11px;letter-spacing:.12em;color:var(--tj-text-secondary)}
html .pod-meta .dot{background:var(--tj-text-muted)}
html .pod-listen{font-size:11px;color:var(--redp);opacity:.9}
html .ppl-role{font-size:11px;letter-spacing:.12em;color:var(--redp);opacity:1}
html .ppl-why{font-size:15px;color:var(--tj-text-caption);line-height:1.6}
html .ppl-h{font-size:11px;letter-spacing:.08em;color:var(--tj-text-secondary)}

/* About: scroll guidance and slideshow HUD text. */
html .sq-pre-scroll,
html .sq-slide-stat,
html .sq-hud-live,
html .sq-hud-title,
html .sq-hud-counter,
html .sq-hint{
  font-size:11px;
  letter-spacing:.12em;
  color:var(--tj-text-caption);
}
html .sq-pre-scroll{letter-spacing:.16em}
html .sq-slide-p{font-size:clamp(15px,1.3vw,17px);color:var(--tj-text-secondary)}
html .sq-slide-stat{
  background:rgba(0,0,0,.56);
  border-color:rgba(255,255,255,.22);
}
html .sq-hud-live{color:var(--redp)}
html .sq-hud-title,
html .sq-hud-counter{color:rgba(var(--cream-rgb),.68)}
html .sq-hint::before{background:rgba(255,255,255,.46)}

/* Art: exhibit and interaction labels must survive image backgrounds. */
html .hero-exhibit-kicker{
  font-size:11px;
  letter-spacing:.14em;
}
html .hero-exhibit-meta{
  font-size:11px;
  letter-spacing:.06em;
  color:rgba(255,255,255,.9);
}
html .c3d-tag{font-size:10px;font-weight:600}

/* Work: page-level labels only; miniature UI inside project artwork is exempt. */
html .hero-ey,
html .we-role,
html .pj-cat,
html .ap-fig,
html .ap-hint{
  font-size:11px;
  color:var(--tj-text-secondary);
}
html .hero-ey{color:var(--redp);letter-spacing:.18em}
html .we-tag{
  font-size:10px;
  color:var(--tj-text-muted);
  border-color:rgba(var(--cream-rgb),.16);
}
html .ap-fig-r{font-size:11px;color:var(--redp)}
html .ap-hint .ap-hint-default{opacity:.9}

@media(max-width:768px){
  html .mob-tab{
    font-size:10px;
    letter-spacing:.06em;
    color:rgba(var(--cream-rgb),.62);
  }
  html .mob-tab.on{color:var(--redp)}
}

/* ── MOBILE TYPE ROLES ────────────────────────────────────────
   Four intentional levels across section-heavy pages:
   10px compact subtype, 11px semantic label/action, 12px metadata,
   15px secondary prose. Desktop declarations remain page-owned. */
@media(max-width:780px){
  html{
    --tj-mobile-subtype:10px;
    --tj-mobile-label:11px;
    --tj-mobile-meta:12px;
    --tj-mobile-copy:15px;
  }

  html .h-cta,
  html .ph,
  html .reel-close,
  html .tc-label,
  html .pc-cta-kicker,
  html .th-eyebrow,
  html .wp-kick,
  html .med-list .med-tag-pill,
  html .exp-badge-live,
  html .wk-row-tags .tag,
  html .wk-united-eyebrow,
  html .wk-deck-eyebrow,
  html .film-pill,
  html .night-museum-kicker,
  html .night-museum-meta,
  html .px-pol2-cap,
  html .px-date,
  html .art-phil-kicker,
  html .sc-kicker,
  html .sc-btn,
  html .folder-tab-label,
  html .folder-source,
  html .illo-more,
  html .sv-close,
  html .sv-explore-text,
  html .sc-bar a{
    font-size:var(--tj-mobile-label);
  }

  html .tunnel-head .th-eyebrow{font-size:var(--tj-mobile-label)}
  html .med-mast-meta,
  html .med-list .med-meta-row,
  html .news-meta{
    font-size:var(--tj-mobile-meta);
    letter-spacing:.12em;
    color:var(--tj-text-caption);
  }

  html .svc-sub,
  html .fly-note,
  html .fly.alt .fly-note,
  html .ew-p-desc,
  html .wk-row-desc,
  html .wk-vault-meta,
  html .sv-desc,
  html .c3d-body,
  html .c3d-sec .c3d-body,
  html .px-body,
  html .c-gift-desc,
  html .pc-cta-desc,
  html .wp-back-desc,
  html .story-close{
    font-size:var(--tj-mobile-copy);
    line-height:1.55;
  }

  html .sc-bar a{color:var(--tj-text-secondary)}
  html .sc-bar a{letter-spacing:.04em;overflow-wrap:anywhere}
  html .sv-explore-text,
  html .story-close{color:var(--tj-text-caption)}

  html .wk-stack-item{font-size:14px;line-height:1.5}
  html .art-pol-cap{font-size:var(--tj-mobile-meta)}
}

/* Local and injected footer variants share one readable metadata scale. */
html .foot-cta-tag,
html .foot-avail,
html .foot-cs-label,
html .foot-globe-leg,
html .foot-s,
html .fb-k,
html .fb-leg,
html .fb-find a{
  font-size:11px;
  color:var(--tj-text-caption);
}
html .foot-email,
html .fb-big .fb-mail{color:var(--tj-text-secondary)}
html .foot-location,
html .fb-loc{font-size:16px;color:var(--tj-text-caption)}
html .foot-globe-leg b,
html .fb-leg b{color:var(--tj-text-muted)}
html .fb-nav a{font-size:16px;color:var(--tj-text-caption)}
html .foot-copy,
html .fb-find-meta .foot-copy{
  font-size:8px;
  color:rgba(var(--cream-rgb),.62);
}
html .foot-made,
html .fb-find-meta .foot-made{
  font-size:8px;
  color:rgba(var(--cream-rgb),.58);
}
html .foot-made em,
html .fb-find-meta .foot-made em{color:var(--redp);opacity:.9}
/* The label sits inline with the links, so it needs the colon to read as a
   lead-in rather than as another list item. */
html .fb-find .fb-k::after{content:":"}

/* Remaining page-level hints and captions. */
html .exp-tag,
html .ew-p-yr,
html .wk-deck-hint,
html .wk-stack-label,
html .wk-pager-dot,
html .pods-group-lbl,
html .news-cta,
html .px-hint,
html .c3d-card-handle,
html .c3d-card-tag,
html .c3d-medium,
html .c3d-location,
html .learnai-invite-kicker,
html .learnai-invite-action,
html .freq{
  font-size:11px;
}
html .exp-tag,
html .ew-p-yr,
html .wk-deck-hint,
html .wk-stack-label,
html .wk-pager-dot,
html .px-hint{color:var(--tj-text-caption)}
html .news-author{font-size:12px;color:var(--tj-text-caption)}
html .news-cta{color:var(--tj-text-secondary)}
html .vid-title-pre{color:var(--tj-text-caption)}
html .sc-sub{color:var(--tj-text-caption)}
html body .clients-lbl{font-size:11px!important;color:var(--tj-text-secondary)}

/* Page-scoped palettes that do not share the site token names.

   --on-hot is the ink for surfaces filled with the accent itself. It cannot be
   one fixed value: measured against each background, near-black reads 3.90:1
   on the Signal blue but 5.14:1 on the warm coral, and white is the exact
   inverse at 5.11:1 and 3.87:1. Hardcoding either one fails a palette, so the
   ink flips with the theme. */
html:not([data-theme="warm"]) .p2-scope,
html:not([data-theme="warm"]) body{
  --coral:#3763e8;      --hot:#3763e8;
  --on-hot:#ffffff;     --on-hot-line:rgba(255,255,255,.34);
}
html[data-theme="warm"] .p2-scope,
html[data-theme="warm"] body{
  --coral:#c96451;      --hot:#c96451;
  --on-hot:#090909;     --on-hot-line:rgba(0,0,0,.25);
}

/* ── SIDE BANNERS ───────────────────────────────────────────────
   The stamp-column drawings are raster assets with the coral baked
   in, so they cannot follow a token. Rotating their hue keeps the
   line work and the greys intact while the accent tracks the theme.

   Values are carried over from theme-blue-dusk: at the source
   coral's near-full chroma the drawings read electric next to a
   softened accent, so saturation is scaled down to match.

   The html prefix outranks each page's own .col-c img rule, which
   declares a transform-only transition.
   ─────────────────────────────────────────────────────────────── */
html .col-c img{
  filter:hue-rotate(var(--art-hue)) var(--art-trim);
  transition:filter .25s ease, transform .25s ease;
}
html .col-c:hover img{
  filter:hue-rotate(var(--art-hue)) var(--art-trim-hover);
}
@media(prefers-reduced-motion:reduce){
  html .col-c img{transition:none}
}

/* Colour of the browser UI chrome follows the accent. */

/* ═══════════════ THEME TOGGLE, rotating badge ═══════════════ */
.tj-theme{
  position:fixed;
  /* clears the stamp column, and sits to the left of the sound toggle
     with their baselines aligned */
  right:calc(var(--col, 0px) + 28px);
  bottom:18px;
  z-index:120;
  width:76px;height:76px;
  display:grid;place-items:center;
  padding:0;
  border:0;
  border-radius:50%;
  background:rgba(17,17,17,.72);
  -webkit-backdrop-filter:blur(10px) saturate(1.4);
  backdrop-filter:blur(10px) saturate(1.4);
  box-shadow:0 0 0 1px rgba(var(--cream-rgb),.14),
             0 10px 30px rgba(0,0,0,.45);
  color:var(--cream);
  cursor:pointer;
  transition:transform .45s cubic-bezier(.22,.61,.36,1),
             box-shadow .45s ease,
             background .45s ease;
}
@media(hover:hover){
  .tj-theme:hover{
    transform:scale(1.06);
    background:rgba(17,17,17,.86);
    box-shadow:0 0 0 1px rgba(var(--red-rgb),.55),
               0 14px 38px rgba(0,0,0,.55);
  }
}
.tj-theme:active{transform:scale(.96)}
.tj-theme:focus-visible{
  outline:2px solid var(--red);
  outline-offset:4px;
}

/* rotating ring of text */
.tj-theme-ring{
  position:absolute;
  inset:0;
  width:100%;height:100%;
  animation:tjSpin 18s linear infinite;
  pointer-events:none;
}
.tj-theme-ring text{
  font-family:var(--fm,'JetBrains Mono',monospace);
  font-size:9.2px;
  font-weight:700;
  letter-spacing:.24em;
  text-transform:uppercase;
  fill:var(--cream);
  opacity:.72;
  transition:fill .45s ease;
}
.tj-theme:hover .tj-theme-ring text{opacity:1;fill:var(--red)}
@keyframes tjSpin{to{transform:rotate(360deg)}}

/* centre glyph, swaps with the mode */
.tj-theme-glyph{
  position:relative;
  width:22px;height:22px;
  display:grid;
  place-items:center;
  pointer-events:none;
}
.tj-theme-glyph svg{
  grid-area:1/1;
  width:22px;height:22px;
  fill:none;
  stroke:var(--red);
  stroke-width:1.6;
  stroke-linecap:round;
  stroke-linejoin:round;
  transition:opacity .4s ease, transform .55s cubic-bezier(.22,.61,.36,1);
}
/* default (Signal) shows the sun, the action is "make it warm" */
.tj-theme-glyph .tj-sun{opacity:1;transform:rotate(0deg) scale(1)}
.tj-theme-glyph .tj-snow{opacity:0;transform:rotate(-90deg) scale(.6)}
html[data-theme="warm"] .tj-theme-glyph .tj-sun{opacity:0;transform:rotate(90deg) scale(.6)}
html[data-theme="warm"] .tj-theme-glyph .tj-snow{opacity:1;transform:rotate(0deg) scale(1)}

/* ── SCROLL TINT ─────────────────────────────────────────────────
   The page ground is driven by scroll-tint.js, which mixes the live
   accent into the page's own background per section.

   The fallback is var(--bg), not a literal, so every page that loads
   this file but never runs the script keeps exactly the ground it has
   today. "html body" only to out-rank each page's own body rule.
   ──────────────────────────────────────────────────────────────── */
html body{
  background-color:var(--tj-tint,var(--bg,#111));
  transition:background-color .9s cubic-bezier(.4,0,.2,1);
}

/* ── THEME CHANGE, CURTAIN SWEEP ─────────────────────────────────
   A full-height panel revealed edge-first with clip-path. Nothing is
   translated or scaled, so the leading edge stays crisp and the panel
   never stretches. It enters from the right, near the badge, and clears
   off the left: one continuous direction, so it reads as a single pass
   rather than a slab bouncing back the way it came.

   The palette is swapped while the screen is covered, so the change
   itself is never seen as a jump.
   ──────────────────────────────────────────────────────────────── */

/* Both accents, readable from either theme, so the panel can be painted
   in the colour it is about to reveal. */
:root{
  --accent-signal:#3763e8;
  --accent-warm:#c96451;
}

.tj-curtain{
  position:fixed;
  inset:0;
  /* the sound toggle parks itself near the top of the integer range, and the
     curtain has to cover it like everything else */
  z-index:2147483600;
  pointer-events:none;
  display:flex;
  align-items:center;
  justify-content:center;
  /* parked: zero width, collapsed against the right edge */
  clip-path:polygon(100% 0%, 100% 0%, 100% 100%, 100% 100%);
  transition:clip-path .46s cubic-bezier(.76,0,.24,1);
}
.tj-curtain.to-warm{background:var(--accent-warm);--tj-curtain-ink:#f7ece0}
.tj-curtain.to-cool{background:var(--accent-signal);--tj-curtain-ink:#eef2f7}

/* covering the viewport */
.tj-curtain.is-cover{clip-path:polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)}
/* continuing off the left, rather than retreating to the right */
.tj-curtain.is-clear{
  clip-path:polygon(0% 0%, 0% 0%, 0% 100%, 0% 100%);
  transition-duration:.54s;
  transition-timing-function:cubic-bezier(.65,0,.35,1);
}
/* snap back to the parked state between sweeps, unanimated */
.tj-curtain.is-parked{transition:none}

.tj-curtain-mark{
  display:flex;
  align-items:center;
  gap:18px;
  color:var(--tj-curtain-ink,#f7ece0);
  opacity:0;
  transform:translateY(12px);
  transition:opacity .26s ease, transform .26s ease;
}
/* the mark arrives once the panel has most of the screen, so it is not
   seen sliding in behind the leading edge */
.tj-curtain.is-cover .tj-curtain-mark{
  opacity:1;
  transform:none;
  transition-delay:.2s;
}
.tj-curtain.is-clear .tj-curtain-mark{
  opacity:0;
  transform:translateY(-10px);
  transition-duration:.2s;
  transition-delay:0s;
}

.tj-curtain-glyph svg{
  display:block;
  width:clamp(32px,3.6vw,48px);
  height:clamp(32px,3.6vw,48px);
  fill:none;
  stroke:currentColor;
  /* heavier than the badge's glyph so it holds its own beside the word */
  stroke-width:1.8;
  stroke-linecap:round;
}
.tj-curtain-glyph .tj-sun circle{fill:currentColor;stroke:none}
.tj-curtain-word{
  font-family:'Geist',system-ui,sans-serif;
  font-weight:500;
  font-size:clamp(30px,4.4vw,60px);
  letter-spacing:-.02em;
  line-height:1;
}

@media(max-width:640px){
  /* On phones the sound toggle is dropped and the theme badge takes its slot,
     just above the bottom nav bar. sfx.js injects its styles into the head at
     runtime, so it lands after this file and wins on source order, hence the
     !important rather than a longer selector. */
  .tjsfx-toggle{display:none!important}
  .tj-theme{
    width:56px;height:56px;
    right:12px;
    bottom:calc(86px + env(safe-area-inset-bottom,0px));
  }
  .tj-theme-ring text{font-size:7.4px;letter-spacing:.2em}
  .tj-theme-glyph,
  .tj-theme-glyph svg{width:18px;height:18px}
}

@media(prefers-reduced-motion:reduce){
  .tj-theme-ring{animation:none}
  .tj-theme,
  .tj-theme-glyph svg{transition:none}
  html body{transition:none}
  .tj-curtain{display:none}
  .tj-theme:hover{transform:none}
}

/* the badge hides while a full-screen overlay owns the viewport */
body.is-loading .tj-theme,
body.nav-open .tj-theme,
body.modal-open .tj-theme{opacity:0;pointer-events:none}
.tj-theme{transition:opacity .3s ease, transform .45s cubic-bezier(.22,.61,.36,1), box-shadow .45s ease, background .45s ease}

@media print{.tj-theme{display:none}}
