/* ============================================================
   EPITHRE — dark theme layer.  DARK_THEME_V1

   SOURCE OF TRUTH for both surfaces:
     - blog     : imported by src/layouts/BaseLayout.astro, AFTER global.css
     - research : deployed byte-identical to VM120 /css/dark.css, linked ONLY
                  from /research/*.  epithre.com's homepage, /about, /models
                  and /strata share about.css + long.css but never load this
                  file, so they stay light and untouched by design.

   PRINCIPLE — this theme is not invented, it is promoted.  The light site
   already carries permanently-dark surfaces (.hero, .callout, footer.site,
   .prose pre): warm-dark ground, bone text, gold accent, batik at
   mix-blend-mode:screen.  Dark mode extends that existing plate language to
   the whole page.  Every value traces back to something already in the brand:
   --navy #6E97C7 is lifted verbatim from `footer .b-dot`, which is how this
   site has always drawn navy on a dark ground.

   PURELY ADDITIVE.  It never edits a light rule, so deleting this file (or
   the data-theme attribute) restores the original site exactly.

   CASCADE RULE — every override is prefixed html[data-theme="dark"], which
   adds (0,1,1) and therefore always out-specifies its light counterpart.
   That cuts both ways: an override can also out-specify a light rule it was
   never aimed at (a :hover, a more-specific variant).  Each such case is
   called out inline.  Declare ONLY the property being changed.
   ============================================================ */


/* ============================================================
   SCREEN-ONLY WRAP.
   The theme is attribute-driven (html[data-theme="dark"]), not
   prefers-color-scheme-driven, so a browser's print-time forcing of light does
   NOT disarm it. Print omits background-color by default but still paints text
   colour, so an un-wrapped layer prints --ink #F0E8D8 onto white paper at
   ~1.2:1 -- a near-blank page. That hits OS-dark readers who never touched the
   toggle, on exactly the long-form research meant to be printed and cited.
   Confining the layer to `screen` makes paper fall back to the untouched light
   cascade, which is what this file already promises: "deleting this file ...
   restores the original site exactly."
   ============================================================ */
@media screen{

/* ---------- tokens ---------- */
html[data-theme="dark"]{
  /* paints UA scrollbars/controls dark — .rail, .table-wrap and pre all scroll */
  color-scheme:dark;

  /* Surfaces keep the light theme's TWO-direction hierarchy rather than
     flattening: special plates sink BELOW the page, cards rise ABOVE it.
     Steps mirror light mode (band->bg 2.9 L*, light was 3.1 L*). */
  --warm-dark:#0C0806;      /* deepest well: hero / callout / footer / pre  L* 2.4 */
  --band:#140E09;           /* sunken band                                  L* 4.4 */
  --bg:#1B1510;             /* page                                         L* 7.3 */
  --surface-raised:#261E16; /* cards: the SURFACE half of --bone's old job  L* 11.9 */
  --card:#2A2119;           /* note blocks                                  L* 13.5 */

  /* --bone is deliberately NOT redefined. It is the brand's text-on-dark
     colour and is already correct; only its SURFACE uses are re-pointed. */

  --ink:#F0E8D8;                        /* 15.4:1 on --bg */
  --ink-soft:rgba(240,232,216,.78);     /*  9.6:1 */
  --ink-faint:rgba(240,232,216,.56);    /*  5.4:1 */
  --rule:rgba(240,232,216,.16);
  --rule-soft:rgba(240,232,216,.08);

  /* Accents invert their physics but keep their semantics: in light, "deep"
     meant darker = more emphasis; on dark, more emphasis = lighter. */
  --soga:#C89055;        /* eyebrows, labels        6.8:1 */
  --soga-deep:#E0BE78;   /* links, emphasis        10.5:1 */
  --navy:#6E97C7;        /* the footer's own navy-on-dark   6.2:1 */
  --gold:#E0BE78;        /* unchanged */

  /* A black shadow on a near-black page is a no-op, so depth here is carried
     by the surface step and the hairline, not by this. Kept for parity. */
  --shadow-card:0 22px 46px -28px rgba(0,0,0,.78);
}

/* ---------- the --bone surface/text split ----------
   --bone is dual-role in the light system: text on dark plates AND the raised
   card surface. Dark mode needs it to stay light for the text role, so every
   SURFACE use is re-pointed. Missing one = a blinding cream slab whose text,
   inheriting the now-light --ink, disappears into it.
   Background ONLY — these cards all have :hover rules at lower specificity. */
html[data-theme="dark"] .band.bone{background:var(--surface-raised)}
html[data-theme="dark"] .featured,
html[data-theme="dark"] .b-card,
html[data-theme="dark"] .r-card{background:var(--surface-raised)}
/* .hero-media.contain is currently unused by any page; re-pointed for system
   consistency. If it ever holds a dark-ink-on-transparent asset, revert it. */
html[data-theme="dark"] .art-hero .hero-media.contain{background:var(--surface-raised)}

/* ---------- batik: the signature ----------
   Megamendung/parang = cream+soga clouds on an indigo ground. On a dark ground
   the brand screens it (.hero::before) so the clouds ADD light rather than the
   indigo muddying the surface. Screen never darkens.

   OPACITY MUST DROP, and the reason is the whole trick of this theme.
   The motif is CREAM. In light mode it is a watermark (peak ΔL* 1.87 above its
   band) not because it was drawn quietly, but because cream-on-cream is a
   coincidence of matching the paper. Re-point that same art at a near-black
   band and the identical alpha yields ΔL* 31 — ~16x the perceived excursion,
   i.e. a marbled slab that fights the text. Parity is therefore impossible:
   matching ΔL* exactly would mean opacity .02, which deletes the motif.

   So the target is not parity, it is the brand's OWN dark-batik loudness:
   the homepage .hero::before ships company-batik at screen/.14 on --warm-dark,
   which measures peak ΔL* 14.1. Every layer below is solved to that figure
   (scaled by its light-mode weight against that same hero), landing each motif
   at peak L* ~16-18 against a page of L* 7.3 — present and glowing, never
   competing with --ink text at L* 92.

   Each layer needs its OWN rule: .art-hero::before (0,2,2) out-specifies both
   .art-hero.has-cover-bg::before (0,2,1) and .b-hero::before (0,1,1), so a
   shared rule declaring opacity would erase the post cover and the index field.
   Verified class combos: index = .art-hero.b-hero, post = .art-hero.has-cover-bg,
   research = .art-hero.has-media (opacity inherited from .art-hero::before). */
html[data-theme="dark"] .art-hero::before{mix-blend-mode:screen;opacity:.12}
html[data-theme="dark"] .art-hero.has-cover-bg::before{mix-blend-mode:screen;opacity:.15}
html[data-theme="dark"] .art-hero.b-hero::before{mix-blend-mode:screen;opacity:.13}
html[data-theme="dark"] .band.batik::before{mix-blend-mode:screen;opacity:.13}
html[data-theme="dark"] .b-wrap::before{mix-blend-mode:screen;opacity:.08}
html[data-theme="dark"] .isx-board::before{mix-blend-mode:screen;opacity:.14}
html[data-theme="dark"] .isx-board::after{mix-blend-mode:screen;opacity:.08}

/* ---------- chrome ---------- */
/* The glass tint is a hardcoded light cream; mirrored to --bg at a higher alpha
   because light text bleeding up through a dark veil reads harder than dark
   text through a light one. The border is a dark alpha = invisible on dark. */
html[data-theme="dark"] header.site{
  background:rgba(27,21,16,.55);
  border-bottom-color:var(--rule-soft);
}

/* The permanently-dark plates now sit on a dark page. In light mode their edge
   came free from the huge value jump against cream; that jump is gone, so they
   need a hairline or they dissolve into the page. --shadow-card cannot do this
   job here (black shadow on near-black). */
html[data-theme="dark"] .hero{border-bottom:1px solid var(--rule-soft)}
html[data-theme="dark"] .callout{border:1px solid var(--rule)}
html[data-theme="dark"] footer.site{border-top-color:var(--rule-soft)}
html[data-theme="dark"] .prose pre{border:1px solid var(--rule-soft)}

/* Ledger opening rules are set to full-strength --ink so they read as
   authoritative against the hairline dividers below. Inverted, a 1.5px
   full-opacity near-white stroke halates and reads as a glowing bar rather
   than structure; --ink-soft restores the intended relative weight. */
html[data-theme="dark"] .ledger,
html[data-theme="dark"] .deflist,
html[data-theme="dark"] .facts{border-top-color:var(--ink-soft)}

/* Reduced-motion swaps the hero video for a poster on a hardcoded #160F0A —
   the LIGHT --warm-dark literal, which would sit as a lighter rectangle inside
   the deeper dark hero. Longhand keeps the poster image from the shorthand. */
@media (prefers-reduced-motion:reduce){
  html[data-theme="dark"] .vframe{background-color:var(--warm-dark)}
}

/* ---------- cards ----------
   Hover border is a hardcoded dark alpha = invisible on dark, so hover would
   appear to DELETE the border. Raised to .28 (vs light's .2) because on dark
   the shadow half of the hover signal is a no-op, leaving border + transform. */
html[data-theme="dark"] .featured:hover,
html[data-theme="dark"] .b-card:hover,
html[data-theme="dark"] .r-card:hover{border-color:rgba(240,232,216,.28)}

/* The card spine is cover art at full strength, and global.css states the intent
   plainly: "batik as a thin full-height vertical spine, title is the focus."
   Light mode delivers that — spine L* 85 sits just under the card's 95 and far
   from the title's 9, so it recedes and the title leads. On dark the card drops
   to L* 12 while the spine stays at 85, which ties the title's 92 — and a solid
   block beats thin letterforms, so decoration starts out-shouting the headline.
   Dimming to .72 lands the spine at L* ~66: unmistakably batik, clearly below
   the title. This restores the light theme's stated hierarchy rather than
   departing from it. (Toning the art, not the identity.) */
html[data-theme="dark"] .featured-media img,
html[data-theme="dark"] .b-card .card-media img{opacity:.72}

/* ---------- prose ----------
   Dark-ink alphas over a light ground vanish on dark; re-expressed as the same
   alpha of --ink. */
html[data-theme="dark"] .prose :not(pre)>code{background:rgba(240,232,216,.07)}
html[data-theme="dark"] .prose thead th{background:rgba(240,232,216,.05)}

/* The link underline is a hardcoded soga brown = invisible on dark, which would
   leave links signalled by colour alone (an a11y regression, not just cosmetic).
   rgba(224,190,120,.4) is gold at .4 — a value the light theme already ships on
   .callout .pse a, so it is established brand.
   BOTH rules required: the first (0,2,2) also out-specifies .prose a:hover
   (0,2,1) and would otherwise kill the hover feedback dead. */
html[data-theme="dark"] .prose a{border-bottom-color:rgba(224,190,120,.4)}
html[data-theme="dark"] .prose a:hover{border-bottom-color:var(--soga-deep)}

/* .prose ol.steps>li::before pairs background:var(--navy) with color:var(--bone).
   --navy is now LIGHT, so bone-on-navy would be light-on-light (2.7:1) and the
   step numerals would silently vanish inside their chips. Flip the numeral to
   the deepest ground (6.6:1); the chip itself is correct as-is. */
html[data-theme="dark"] .prose ol.steps>li::before{color:var(--warm-dark)}

/* Reading-progress takes its colour from a per-post inline style (the category
   accent), so no selector can out-specify it. filter is untouched by that inline
   declaration, so no !important is needed — and brightness lands the four dark
   accents almost exactly on the tokens' own answers (#2C4A6F -> ~#5189CD ~=
   --navy; #7A4E2D -> ~#E29053 ~= --soga), keeping per-category hue. */
html[data-theme="dark"] .read-progress{filter:brightness(1.85) saturate(.95)}

/* ============================================================
   RESEARCH DIAGRAM (.isx-fig2, /research/di-balik-isonai-ison-search/)
   The figure declares its own local token block, so re-theming is mostly a
   token swap.
   TRAP: --gold and --card exist in BOTH :root and .isx-fig2. Writing
   `--gold:var(--gold)` here resolves against the LOCAL name, not :root — a
   self-reference cycle that makes the property invalid-at-computed-value and
   silently deletes the corner ticks. Those two MUST be literals.
   ============================================================ */
html[data-theme="dark"] .isx-fig2{
  --nv:#6E97C7;                /* = --navy */
  --nv2:#8FB0D8;               /* lifted so the gradient still runs light->lighter */
  --gold:#E0BE78;              /* LITERAL — var(--gold) here would cycle */
  --card:#2A2119;              /* LITERAL — var(--card) here would cycle */
  --brd:var(--surface-raised);
  --line:var(--rule);
  --tx:var(--ink);
  --tx2:var(--ink-soft);
  --tx3:var(--ink-faint);
  --grn:#5FA37B;               /* lifted from #3E7C5A: 3.2:1 -> 5.3:1 for .isx-k text */
}
/* Glyphs sit on gradient chips that are now LIGHT blue/green. White would drop
   to 3.0:1 and 2.2:1 across the gradient; the deepest ground gives 6.6-9.4:1. */
html[data-theme="dark"] .isx-picked .isx-ic,
html[data-theme="dark"] .isx-ai .isx-ic,
html[data-theme="dark"] .isx-src .chk svg{color:var(--warm-dark)}
html[data-theme="dark"] .isx-out .isx-ic{
  background:linear-gradient(135deg,var(--grn),#7CC09A);
  color:var(--warm-dark);
}
/* Navy-tinted fills expressed as dark-navy alphas over ivory: invisible on dark. */
html[data-theme="dark"] .isx-ic{background:rgba(110,151,199,.14)}
html[data-theme="dark"] .isx-m{background:rgba(110,151,199,.12);border-color:rgba(110,151,199,.30)}
html[data-theme="dark"] .isx-picked{background:linear-gradient(135deg,rgba(110,151,199,.14),var(--card))}
html[data-theme="dark"] .isx-out{
  background:linear-gradient(135deg,rgba(95,163,123,.20),var(--card));
  border-color:rgba(95,163,123,.42);
}
/* The wordmark hardcodes the light ink + light-mode dot. */
html[data-theme="dark"] .isx-fig2 .isx-ph b{color:var(--ink)}
html[data-theme="dark"] .isx-fig2 .isx-ph b .isx-dot{color:var(--navy)}

/* ============================================================
   THEME TOGGLE
   Deliberately quiet. The batik is where this theme spends its boldness; the
   control that reveals it should not compete. Matches .lang-switch's weight so
   the nav keeps one voice. Tokens carry it — it needs no dark override.
   ============================================================ */
.theme-toggle{
  -webkit-appearance:none;appearance:none;
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;padding:0;
  background:none;border:1px solid var(--rule);border-radius:5px;
  color:var(--ink-faint);cursor:pointer;
  transition:color .15s,border-color .15s;
}
.theme-toggle:hover{color:var(--soga);border-color:var(--soga)}
.theme-toggle svg{width:15px;height:15px;display:block}
.theme-toggle .t-moon{display:block}
.theme-toggle .t-sun{display:none}
html[data-theme="dark"] .theme-toggle .t-moon{display:none}
html[data-theme="dark"] .theme-toggle .t-sun{display:block}
/* progressive enhancement — the control does nothing without JS */
html:not(.js) .theme-toggle{display:none}

/* The mobile drawer styles `nav.top a` only, so a <button> gets none of the row
   treatment. It does not need much: nav.top is align-items:center, so the button
   already centres itself into the column exactly like the EN/ID chip it sits
   beside — it only lacks that row's vertical rhythm. */
@media (max-width:760px){
  html.js nav.top .theme-toggle{margin-top:11px}
}

/* The toggle costs nav.top 30px + a 24px gap = 54px, but between the drawer
   breakpoint (761px) and ~800px the English bar has only 37px of headroom. It
   therefore wraps to two rows and the sticky header doubles, 68px -> 120px —
   and iPad portrait is 768px, squarely inside that band. Tightening the nav
   rhythm just there buys 8px x 8 gaps = 64px, comfortably more than the 17px
   shortfall, and touches no other width.
   NOT scoped to [data-theme=dark]: the toggle ships in BOTH themes, so this
   layout correction must apply in both. */
@media (min-width:761px) and (max-width:800px){
  nav.top{gap:16px}
}


/* ============================================================
   /whatis — etymology + brand kit (whatis.css).
   Mostly tokenised already, so this is small. The one real decision is the brand
   stage; see below.
   ============================================================ */

/* --bone used as a SURFACE again — same split as everywhere else. */
html[data-theme="dark"] .pronounce,
html[data-theme="dark"] .etym-part,
html[data-theme="dark"] .brand-card,
html[data-theme="dark"] .brand-spec{background:var(--surface-raised)}

/* dark-ink alpha over ivory = invisible on dark; --ink at 1.5px full strength
   halates into a glowing bar (same call as the ledger rules above). */
html[data-theme="dark"] .mapping-head-row{
  background:rgba(240,232,216,.05);
  border-bottom-color:var(--ink-soft);
}
/* permanently-dark plate: needs an edge once the page around it is dark too */
html[data-theme="dark"] .pullquote{border:1px solid var(--rule)}

/* ---------- brand specimens do NOT theme ----------
   .brand-stage is a swatch, not UI. The mark it displays is a fixed-colour asset
   (brandmark.svg is #1F1812 ink + #2C4A6F navy) drawn for a light ground, and the
   kit already ships a separate "Reversed" card for the dark treatment. Inverting
   the stage would erase the exact thing the page exists to show — the same reason
   .swatch .chip hardcodes its hex. So the stage keeps its light ground in both
   themes; only the card chrome around it follows the theme.
   :not(.dark) is required — without it these rules (0,3,x) would out-specify
   .brand-stage.dark .bm-word (0,2,1) and break the Reversed card. */
html[data-theme="dark"] .brand-stage:not(.dark){
  background:#EFE9D8;
  border-bottom-color:rgba(31,24,18,.16);
}
html[data-theme="dark"] .brand-stage:not(.dark) .bm-word,
html[data-theme="dark"] .brand-stage:not(.dark) .bm-word.mono,
html[data-theme="dark"] .brand-stage:not(.dark) .bm-word.mono .b-dot{color:#1F1812}
html[data-theme="dark"] .brand-stage:not(.dark) .bm-word .b-dot{color:#2C4A6F}
/* the monogram tile is a specimen too — pin it to the spec'd warm-dark, not the
   theme's deeper one */
html[data-theme="dark"] .brand-stage:not(.dark) .bm-tile{background:#160F0A}


/* ---------- the Trivium diagram ----------
   An INLINE <style> block hardcodes this SVG's ink: .tri-stroke/.tri-label at
   #1F1812 and .tri-sub at rgba(31,24,18,.6) — all invisible on a dark page. It was
   missed on the first pass because the audit read whatis.css and not the page's
   own inline style.
   Unlike .brand-stage, this one SHOULD follow the theme: it is a figure explaining
   the content, not a specimen of a fixed-colour asset, and it is inline SVG we own
   rather than an external file. So it just maps onto the tokens. */
html[data-theme="dark"] .tri-stroke{stroke:var(--ink-soft)}
html[data-theme="dark"] .tri-label{fill:var(--ink)}
html[data-theme="dark"] .tri-sub{fill:var(--ink-faint)}
html[data-theme="dark"] .tri-center,
html[data-theme="dark"] .tri-dot{fill:var(--navy)}

} /* end @media screen */

/* .theme-toggle's base styles live only in this file and are inside the wrap,
   so on paper the button would render as an unstyled default control. It is
   also useless on paper. */
@media print{ .theme-toggle{display:none} }
