James Zhan in real life.

Changelog

A log of the changes I’ve made to the blog.

2026-07-25

2026-07-21

2026-07-20

V4.7.2

2026-07-19

2026-07-16

2026-07-15

2026-07-14

2026-07-13

2026-07-11

2026-07-10

    main > p.tags a:not(:first-child)::before{
      content:"·";
      margin:0 0.5em;
      color:var(--text-color);
      opacity:0.5;
    }

2026-07-09

2026-07-08

    h1:not(:has(+ p > i > time)){
      margin-bottom: 0.8em;   
    }

2026-07-07

h1, h2, h3, h4, h5, h6,
sup.footnote-ref {
  scroll-margin-top: 100px;
}

2026-07-06

V4.5

2026-07-05

2026-07-03

2026-07-02

2026-07-01

    a[target="_blank"]::after {
      content: " ↗";
    }

2026-06-29

2026-06-27

<script src="https://cdn.jsdelivr.net/gh/froodooo/bear-plugins@0.0.44/bear/blog-posts.js"></script>

Source

2026-06-26

V4.2.1:

2026-06-24

V4.2 Typography overhaul:

2026-06-19

    kbd{
      font-family:var(--font-mono);
      font-weight:700;
      font-size:0.9em;
      padding:0.3em 0.7em 0.35em;
      border-radius:3px;
      white-space:nowrap;
      color:#2c2c2c;
      background:linear-gradient(#fafafa, #e3e3e3);
      border:1px solid #bfbfbf;
      box-shadow:
      inset 0 2px 0 #ffffff,          /* glossy domed top */
      0 4px 0 #c4c4c4,                /* the tall keycap wall */
      0 6px 5px rgba(0,0,0,0.25);     /* shadow cast on the page */
    }
    @media (prefers-color-scheme:dark){
      kbd{
        color:#f0ede4;
        background:linear-gradient(#474747, #2f2f2f);
        border-color:#1c1c1c;
        box-shadow:
        inset 0 2px 0 rgba(255,255,255,0.14),
        0 4px 0 #1d1d1d,
        0 6px 5px rgba(0,0,0,0.55);
      }
    }
How is this achieved?

Full disclosure: I have zero background in HTML/CSS so I got the code from Claude. However, I tested the code to make sure it worked the way I wanted it to in CodeRunner before putting it in the theme of my Bear Blog.

Put this in the global CSS:

    :root{ --img-overflow: 150px; } /* this determines how much a wide image exceeds the paragraph width */

    main img.wide{
      /* never poke out more than the space actually available,
      so narrow screens don't get a horizontal scrollbar */
      --_overflow: max(0px, min(var(--img-overflow), calc((100vw - 100%) / 2 - 8px)));
      width: calc(100% + 2 * var(--_overflow));
      max-width: none;
      margin-inline: calc(-1 * var(--_overflow));  /* breaks out, stays centered */
    }
    
    @media (max-width: 540px){   /* KNOB: below this width, no breakout */
      main img.wide{
        width: 100%;
        margin-inline: 0;
      }
    }

Then put this script in the footer directive:

<script>
  // Widen landscape photos in the post body; leave portraits at column width.
  (function () {
    // KNOB: only widen images whose width/height ratio is at least this.
    // 1 = any landscape image. Raise toward ~1.2 to skip near-square photos.
    var MIN_LANDSCAPE_RATIO = 1;
    
    function classify(img) {
      if (!img.naturalWidth || !img.naturalHeight) return;  // not measurable yet
      if (img.naturalWidth / img.naturalHeight >= MIN_LANDSCAPE_RATIO) {
        img.classList.add('wide');
      }
    }
    
    function run() {
      // content images only: inside <main>, skipping galleries + opted-out images
      var imgs = document.querySelectorAll('main img:not(.no-style):not(.inline)');
      imgs.forEach(function (img) {
        if (img.closest('.bear-gallery')) return;  // skip gallery thumbnails
        if (img.complete) classify(img);
        else img.addEventListener('load', function () { classify(img); });
      });
    }
    
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', run);
    } else {
      run();
    }
  })();
</script>

2026-06-17

Major blog theme redesign! It’s now on V4. Homepage got its own design from the rest of the site. Will be writing a blog post about it, but here’s a quick overview of the changes:

2026-02-26

2026-02-10

2026-02-05

2026-02-02

2026-01-31

2026-01-23

2026-01-19

I recently discovered the Menlo typeface through Diarly and fell in love with it. Most monospace typefaces remind me of coding and programming, but Menlo doesn’t. Shortly after, I coincidentally discovered that if you set the font-family to just monospace, the browser on Apple devices will default it to Menlo, so I thought I would just do that instead of using the self-hosted IBM Plex Mono and save some kb in the font loading. I know on non-Apple devices it won’t be Menlo, but I don’t mind that either.

2026-01-06

    main ul li,
    main ol li{
      margin-bottom: calc((var(--post-leading) - 1) * 1em);
    }

2026-01-05

a:hover{
  background-color:var(--main-color);
  color:#fff;
}

a:hover:has(img){
  background-color:transparent;
  color:inherit;
}

a img{
  display:inline-block;
  cursor:pointer;
  transition:transform 0.18s ease;
}

a:hover img{
  transform:translateY(-2px);
}

2026-01-04

2025-12-30

2025-12-26

2025-12-22

2025-12-21

.footnotes {
  font-size: 0.8em;
}

.footnotes p {
  margin: 0;
}

.footnotes li {
  margin-bottom: 0.3em;
}

2025-12-19

    /* Same-page jump links like <a href=“#section”> */
      main a[href^=“#”]:not([href=“#”]):not(.inline-toc a) {
      border-bottom-width: **0px**;                    /* thicker underline just for jump links */
      font-size: calc(var(—font-scale) * **0.8**);   
      font-weight: **500**;                            
    }
    
    .inline-toc a[href^=“#”] {
      font-size: inherit;
      font-weight: inherit;
    }

2025-11-30

2025-11-16

2025-11-12

2025-11-10

2025-11-08

2025-11-07

2025-11-06