/* moloo4ni.neocities.org
   fixed 720px layout in the spirit of early-2000s personal sites.
   navigation is a real <table>; per-section accent colour is set
   by a class on <body> (about / notes / projects / contact / links). */

:root {
  --grid: #1a1a6e;      /* navigation grid lines */
  --hl: #ffffb3;        /* active cell highlight */
  --box: #ececec;       /* content background */
  /* every page sets its own accent through the body class below.
     this fallback is deliberately not --grid, so a page that forgets
     the class looks off instead of silently merging into the grid. */
  --accent: #555555;
}

body.about    { --accent: #c62828; }
body.notes    { --accent: #2e7d32; }
body.projects { --accent: #b7791f; }
body.contact  { --accent: #00796b; }
body.links    { --accent: #6a1b9a; }

/* ---- base ---- */

html { background: #fff; }

body {
  margin: 0;
  padding: 24px 0 40px;
  color: #222;
  font: 13px/1.5 Verdana, Geneva, sans-serif;
}

a { color: #1a1a6e; }
a:hover { color: var(--accent); }

.page { width: 720px; margin: 0 auto; }

/* ---- navigation grid ---- */

.nav {
  width: 720px;
  border-collapse: collapse;
  table-layout: fixed;
  margin: 0;
}

/* no explicit cell width: fixed layout splits the 720px evenly,
   so the grid stays exactly as wide as the frame below it. */
.nav td {
  border: 2px solid var(--grid);
  padding: 0;
  vertical-align: bottom;
}

.nav tr.main td { height: 78px; }
.nav tr.sub td  { height: 25px; }

.nav td.cur { background: var(--hl); }

.nav a {
  display: block;
  position: relative;
  padding: 6px 8px;
  color: var(--grid);
  font-weight: bold;
  text-decoration: none;
}

.nav tr.main a { height: 66px; box-sizing: border-box; }
.nav tr.sub  a { height: 25px; box-sizing: border-box; padding: 3px 8px; }

.nav a:hover { color: var(--accent); }

.nav tr.main a img {
  position: absolute;
  top: 6px;
  right: 8px;
  width: 48px;
  height: 48px;
}

.nav tr.main a span {
  position: absolute;
  left: 8px;
  bottom: 4px;
}

/* ---- framed content ---- */

.frame {
  display: flex;
  align-items: stretch;
  /* the negative margin pulls the frame onto the grid's bottom line;
     position + z-index say explicitly which border wins, instead of
     relying on the default paint order for overlapping boxes. */
  position: relative;
  z-index: 1;
  margin-top: -2px;
}

.side {
  width: 60px;
  flex: none;
  box-sizing: border-box;
  border: 2px solid var(--accent);
  /* one 2px rule every 80px, so the strip reads as a column of 60×80
     cells like the reference. counted from the outer edge, so at the
     box's 400px height the fifth rule lands exactly on the bottom border. */
  background-origin: border-box;
  background-image: repeating-linear-gradient(
    to bottom,
    transparent 0 78px,
    var(--accent) 78px 80px
  );
}

/* the strips give up the border they share with the box, so the box keeps
   its full frame on narrow screens, where the strips are gone. */
.frame .side:first-child { border-right: 0; }
.frame .box + .side      { border-left: 0; }

.box {
  flex: 1;
  /* a flex item refuses to shrink below its content by default, which
     would let an unbreakable string widen the frame past 720px even
     with overflow-wrap set. min-width: 0 lets the break actually win. */
  min-width: 0;
  box-sizing: border-box;
  /* fixed, not min: five 80px cells whatever the page holds. anything
     longer scrolls inside .scroll, the way the reference does it. */
  height: 400px;
  /* the right gutter is split: 20px here, then the bar, then 20px of
     .scroll padding, so text still ends 60px from the frame. */
  padding: 40px 20px 40px 60px;
  background: var(--box);
  border: 2px solid var(--accent);
  overflow: hidden;
  /* a long url or path has no break opportunity and would otherwise
     push past the fixed 720px and out of the frame. */
  overflow-wrap: break-word;
}

/* the wrapper scrolls, not .box itself: that keeps the bar inside the
   padding and clips text at the padding edge instead of at the frame. */
.scroll {
  height: 100%;
  overflow-y: auto;
  padding-right: 20px;
  /* reserve the bar's column on short pages too, so the text column is
     the same width on every page. */
  scrollbar-gutter: stable;
}

/* white track in a grid-coloured frame, thumb in the section accent and
   inset 2px so the frame shows around it. chromium/webkit take the
   pseudo-elements; firefox does not know them and gets scrollbar-color
   instead. the guard matters: chromium (121+) drops the pseudo-elements
   as soon as scrollbar-color is set. */
.scroll::-webkit-scrollbar { width: 20px; }
.scroll::-webkit-scrollbar-track {
  background: #fff;
  border: 2px solid var(--grid);
}
.scroll::-webkit-scrollbar-thumb {
  background: var(--accent);
  border: 2px solid transparent;
  background-clip: padding-box;
}
@supports not selector(::-webkit-scrollbar) {
  .scroll {
    scrollbar-width: auto;
    scrollbar-color: var(--accent) #fff;
  }
}

.box h2 {
  margin: 0 0 16px;
  font-size: 13px;
  font-weight: bold;
}

.box h3 {
  margin: 20px 0 4px;
  font-size: 13px;
  font-weight: bold;
}

.box p  { margin: 0 0 12px; }

/* both dimensions are fixed and match the width/height attributes in the
   markup, so the box is reserved before the image arrives and nothing
   shifts on load. avatar-240.png is exactly 240×320, i.e. the same 3:4. */
.box .avatar {
  float: right;
  width: 120px;
  height: 160px;
  margin: 0 0 12px 24px;
}

/* notes / projects entries */

.entry { margin: 0 0 20px; }
.entry h3 { margin: 0 0 2px; }
.entry h3 a { text-decoration: none; }
.entry h3 a:hover { text-decoration: underline; }

/* ---- footer ---- */

footer { margin: 12px 0 0 120px; }

footer .name { margin: 0 0 12px; font-weight: bold; }

/* flex instead of line-height: 0. both kill the baseline gap under an
   inline image, but line-height: 0 also collapses any text in the
   paragraph to nothing, so alt text on a missing badge would vanish. */
footer .badges {
  margin: 0 0 10px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
footer .badges img { display: block; }

footer .updated { margin: 0; color: #666; font-size: 11px; }

/* ---- narrow screens ----
   the desktop layout stays fixed at 720px. below that the page goes
   fluid, the decorative side strips drop out and the nav shrinks. */

@media (max-width: 760px) {
  body { padding: 12px 0 24px; }

  .page { width: auto; margin: 0 12px; }

  /* an explicit width, not auto: table-layout: fixed only applies when
     the table has one, and without it the cells shrink to their content
     and the labels break letter by letter. */
  .nav { width: 100%; }

  .side { display: none; }

  /* cells are 91–147px here, too narrow for a 48px icon beside the label.
     fill the cell and shrink the icon so it sits fully above the label:
     icon y 6–46, label line y ~52–72 — no overlap whatever the cell width. */
  .nav tr.main a { height: 76px; }
  .nav tr.main a img { width: 40px; height: 40px; }

  /* no side strips to line up with, and a nested scroll is awkward on
     a phone: let the box grow with its content instead. */
  .box {
    height: auto;
    overflow: visible;
    padding: 24px 20px;
  }

  .scroll {
    height: auto;
    overflow: visible;
    padding-right: 0;
    scrollbar-gutter: auto;
  }

  .box .avatar { margin-left: 16px; }

  footer { margin: 12px 12px 0; }
}

@media (max-width: 480px) {
  /* no room for icon and label side by side: keep the label. */
  .nav tr.main a img { display: none; }

  /* five cells in ~300px leave ~55px each for a bold label: "projects"
     needs the smaller size to fit on one line. break-word stays only as
     the fallback for a viewport narrower than that. */
  .nav a { font-size: 11px; }

  .nav tr.main td { height: 48px; }
  .nav tr.main a  { height: 36px; padding: 4px 5px; }

  .nav tr.main a span {
    left: 5px;
    right: 5px;
    overflow-wrap: break-word;
  }

  .nav tr.sub a { padding: 3px 5px; }

  .box { padding: 20px 14px; }

  /* a 120px float leaves ~150px of text: let it sit on its own line. */
  .box .avatar {
    float: none;
    display: block;
    margin: 0 0 16px;
  }
}
