Thanks to visit codestin.com
Credit goes to levels.io

, not inside the chart sections, so they need naming separately. */ .blogstats, .evchart, .folchart, .sentchart, .subchart, .tagwall, .vcfund, .fol-tip, .sc-tip, .svot-tip, .vcf-tip { font-variant-numeric: tabular-nums; } * { box-sizing: border-box; } html { background: var(--bg); } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; background: var(--bg); color: var(--fg); line-height: 1.65; margin: 0; } .theme-toggle { position: absolute; top: 1rem; right: 1rem; z-index: 10; background: none; border: none; cursor: pointer; font-size: 1.2rem; line-height: 1; padding: .35rem; color: var(--muted); opacity: .7; } .theme-toggle:hover { opacity: 1; } .subscribe-top { position: absolute; top: 1rem; right: 3.2rem; z-index: 10; background: var(--accent); color: #fff; font-size: .8rem; font-weight: 600; padding: .35em .85em; border-radius: 6px; border: 1px solid var(--accent); } /* Same hover treatment as .catch-emails-button: outlined ghost style. */ .subscribe-top:hover { background: none; color: var(--accent); text-decoration: none; } .wrap { max-width: 42rem; margin: 0 auto; padding: 3rem 1.25rem 5rem; } a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } header.site { margin-bottom: 2.5rem; } header.site h1 { font-size: 1.4rem; margin: 0; } header.site h1 a { color: var(--fg); } header.site p { color: var(--muted); margin: .35rem 0 0; } .year { color: var(--heading); font-weight: 700; margin: 2.5rem 0 .75rem; font-size: 1.4em; } /* Date separator inside a post list — centred label with a hairline rule running out to each side. Used for both granularities (month when the list is dense, year when it isn't), so the two never look different. Distinct from .year, which is a section heading (Pinned, Related posts). */ .datesep { display: flex; align-items: center; gap: .75em; color: var(--muted); font-weight: 700; font-size: 1em; margin: 1.7rem 0 .6rem; } .datesep::before, .datesep::after { content: ""; flex: 1 1 0; height: 1px; background: var(--border); } .datesep a { color: inherit; text-decoration: none; } .datesep a:hover { color: var(--accent); text-decoration: underline; } .meta a { color: inherit; text-decoration: none; } .meta a:hover { color: var(--accent); text-decoration: underline; } .posts + .datesep { margin-top: 1.4rem; } ul.posts { list-style: none; padding: 0; margin: 0; } ul.posts li { display: flex; gap: 1rem; padding: .35rem 0; align-items: baseline; } ul.posts li time { color: var(--muted); font-variant-numeric: tabular-nums; font-size: .85rem; white-space: nowrap; flex: none; width: 4.6rem; } ul.posts li a { font-weight: 700; } ul.posts li .from-x { color: var(--muted); font-size: .85em; flex: none; margin-left: auto; } .draft-badge { font-size: .68em; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #b45309; background: #fef3c7; border-radius: 4px; padding: .1em .4em; flex: none; } html[data-theme="dark"] .draft-badge { color: #fcd34d; background: #3a2e0c; } .draft-notice { font-size: .9em; font-weight: 600; color: #b45309; background: #fef3c7; border-radius: 6px; padding: .4em .7em; margin: 0 0 1rem; display: inline-block; } html[data-theme="dark"] .draft-notice { color: #fcd34d; background: #3a2e0c; } /* "Covers" toggle: clickable thumbnail (or empty placeholder) after the date. */ ul.posts li .cover-link { flex: none; line-height: 0; } ul.posts li .cover-thumb { display: block; width: 72px; height: 48px; object-fit: cover; border-radius: 4px; background: var(--border); transition: opacity .15s; } ul.posts.covers li { align-items: center; } /* Cap listing titles at 2 lines so a long title never wraps to 3+ and leaves the date/thumbnail floating in the middle. Full title shows on hover + the post page. */ ul.posts.covers li a:not(.cover-link) { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; min-width: 0; } /* Thumb + title behave as one link: hovering either underlines the title and dims the thumb; clicking dims it further. */ ul.posts li:has(.cover-link:hover) a:not(.cover-link) { text-decoration: underline; } ul.posts li .cover-link:hover .cover-thumb, ul.posts li:has(a:not(.cover-link):hover) .cover-thumb { opacity: .75; } ul.posts li .cover-link:active .cover-thumb, ul.posts li:has(a:not(.cover-link):active) .cover-thumb { opacity: .5; } .sort-sep { margin-left: 1rem; } .notice { text-align: center; font-size: 1.3rem; font-weight: bold; line-height: 1.5; margin: 1rem 0 2.5rem; color: var(--heading); } .notice a { color: var(--accent); } article h1.title { font-size: 2rem; line-height: 1.2; margin: 0 0 .25rem; } article .meta { color: var(--muted); font-size: .9rem; margin-bottom: .75rem; } article .meta .meta-link { color: inherit; text-decoration: none; } article .meta .meta-link:hover { text-decoration: underline; } .post-tags { margin-bottom: 2rem; display: flex; flex-wrap: wrap; gap: .5rem; } .post-tags a { font-size: .8rem; font-weight: 600; color: var(--accent); border: 1px solid var(--border); border-radius: 999px; padding: .15rem .7rem; } .post-tags a:hover { text-decoration: none; background: var(--accent); color: #fff; border-color: var(--accent); } .tags-index { margin-top: 1.5rem; } .tags-index .tag-count { color: var(--muted); font-weight: 400; } .tags-index a:hover .tag-count { color: #fff; } article img, article video { max-width: 100%; height: auto; border-radius: 4px; display: block; margin: 1.75rem auto; } /* Ghost image figures: kill the browser's default 40px figure margin + center */ article figure.kg-image-card, article figure.kg-card-hascaption { margin: 1.75rem 0; text-align: center; } article figure.kg-image-card img, article figure.kg-card-hascaption img { margin: .5rem auto; } article figcaption { color: var(--muted); font-size: .85rem; margin-top: .4rem; text-align: center; } article img { background-color: var(--code-bg); background-image: linear-gradient(90deg, transparent, rgba(128,128,128,.12), transparent); background-size: 200% 100%; animation: img-shimmer 1.4s ease-in-out infinite; } article video { width: 100%; background: #000; } @keyframes img-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } figure.kg-embed-card { margin: 2rem 0; } figure.kg-embed-card iframe { max-width: 100%; } figure.kg-embed-card .twitter-tweet, figure.kg-embed-card .twitter-tweet-rendered { width: 100% !important; max-width: 100% !important; margin-left: auto; margin-right: auto; } figure.kg-embed-card .twitter-tweet-rendered iframe { width: 100% !important; max-width: 100% !important; } /* YouTube/Vimeo oembed iframes ship with fixed width/height attrs. Many old posts have them BARE (not wrapped in figure.kg-embed-card), so the generic `article iframe{height:auto}` rule below collapsed them to the 150px iframe default — the "weirdly short" players. Target both wrapped and bare embeds and give them a responsive 16:9 box. */ figure.kg-embed-card iframe[src*="youtube.com/embed"], figure.kg-embed-card iframe[src*="player.vimeo.com"], article iframe[src*="youtube.com/embed"], article iframe[src*="youtube-nocookie.com/embed"], article iframe[src*="player.vimeo.com"] { width: 100%; height: auto; aspect-ratio: 16/9; display: block; margin: 1.5rem auto; } figure.kg-bookmark-card { position: relative; display: flex; margin: 1.5rem 0; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; min-height: 116px; } .kg-bookmark-container { position: absolute; inset: 0; z-index: 1; } .kg-bookmark-content { padding: 1rem 1.1rem; flex: 1 1 auto; min-width: 0; } .kg-bookmark-title { font-weight: 600; color: var(--fg); } .kg-bookmark-description { color: var(--muted); font-size: .9rem; margin-top: .4rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .kg-bookmark-metadata { margin-top: .6rem; font-size: .8rem; color: var(--muted); display: flex; align-items: center; gap: .5rem; } .kg-bookmark-icon { width: 18px; height: 18px; border-radius: 3px; background: none; animation: none; } .kg-bookmark-thumbnail { flex: 0 0 34%; max-width: 200px; } .kg-bookmark-thumbnail img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 0; } @media (max-width: 480px) { .kg-bookmark-thumbnail { display: none; } } /* Internal "embed the post" card — replaces a tweet embed that's also a post here. */ figure.post-embed-card { display: flex; margin: 2rem 0; } .pec-link { display: flex; flex: 1; min-width: 0; text-decoration: none; overflow: hidden; border: 1px solid var(--border); border-radius: 8px; min-height: 96px; transition: border-color .1s; } .pec-link:hover { border-color: var(--accent); } .pec-content { padding: 1rem 1.1rem; flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; } .pec-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: .35rem; } .pec-title { font-weight: 600; color: var(--fg); line-height: 1.3; } .pec-thumb { flex: 0 0 34%; max-width: 200px; } .pec-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; } @media (max-width: 480px) { .pec-thumb { display: none; } } article h2 { margin-top: 2rem; } article pre { background:var(--code-bg); padding:1rem; overflow:auto; border-radius:6px; } article code { background:var(--code-bg); padding:.15em .35em; border-radius:3px; font-size:.9em; } article pre code { background:none; padding:0; } article blockquote { border-left:3px solid var(--border); margin:1.5rem 0; padding:.2rem 0 .2rem 1rem; color:var(--quote); } article table { border-collapse: collapse; width: 100%; margin: 1.5rem 0; font-size: .92em; display: block; overflow-x: auto; } article th, article td { text-align: left; padding: .5rem .7rem; border-bottom: 1px solid var(--border); white-space: nowrap; } article th { font-weight: 700; color: var(--heading); border-bottom: 2px solid var(--border); } article tbody tr:hover { background: var(--code-bg); } article tr.exited-row { background: #dcfce7; } article tr.exited-row:hover { background: #c7f0d6; } html[data-theme="dark"] article tr.exited-row { background: #14321f; } html[data-theme="dark"] article tr.exited-row:hover { background: #1b432a; } article blockquote > :first-child { margin-top:0; } article blockquote > :last-child { margin-bottom:0; } .backlink { display:inline-block; margin-bottom:2rem; color:var(--muted); } /* Post page top row: backlink left, edit button pushed to the right. */ .post-topbar { display:flex; justify-content:space-between; align-items:baseline; gap:1rem; } .post-topbar .backlink { margin-bottom:2rem; } .edit-link { color: var(--accent); font-size: .82em; white-space: nowrap; } ul.posts li .edit-link { flex: none; margin-left: auto; } ul.posts li .from-x ~ .edit-link { margin-left: .5rem; } footer.site { margin-top: 4rem; color: var(--muted); font-size: .85rem; } .site-search { margin: 0 0 1rem; } /* Same visual language as the newsletter email box: white field, blue ring, soft shadow (email box keeps its flat right edge for the button). */ .site-search input { width: 100%; padding: 19px; font-size: 15px; color: #3c484e; background: #fff; border: none; border-radius: 6px; outline: none; box-shadow: 0 0 0 1px var(--accent), 0 2px 4px 0 rgb(0 0 0 / 7%), 0 1px 1.5px 0 rgb(0 0 0 / 5%); } .site-search input:focus { box-shadow: 0 0 0 2px var(--accent), 0 2px 4px 0 rgb(0 0 0 / 7%); } /* Dark mode: dark field, quiet border (the white field + blue ring glared). */ html[data-theme="dark"] .site-search input { background: var(--bg); color: var(--fg); box-shadow: 0 0 0 1px var(--border); } html[data-theme="dark"] .site-search input:focus { box-shadow: 0 0 0 1px var(--accent); } .topnav { color: var(--muted); font-size: .85rem; margin: 0 0 1.6rem; } .search-sort { color: var(--muted); font-size: .85rem; margin-top: .5rem; } .search-sort-filter { margin-top: .15rem; } .search-sort strong { color: var(--fg); } ul.search-results { list-style: none; padding: 0; margin: 1.5rem 0 0; } ul.search-results li { margin: 0 0 1.5rem; } ul.search-results li a { font-weight: 700; } ul.search-results time { display: block; color: var(--muted); font-size: .8rem; margin-top: .15rem; } .snippet { color: var(--muted); margin: .3rem 0 0; font-size: .92rem; } .site-credit { margin-top: .8rem; font-size: .8em; color: var(--muted); } .post-source { margin-top: 2rem; color: var(--muted); } .post-ps { margin-top: 0; color: var(--fg); } hr { background-color: var(--hr); height: 1px; width: 100%; border-style: none; margin: 28px 0; } .post-nav { display: flex; justify-content: space-between; gap: 1.5rem; } .post-nav .prev, .post-nav .next { flex: 0 1 50%; } .post-nav .next { margin-left: auto; } .post-nav a { font-weight: 700; display: flex; align-items: center; gap: .4em; } .post-nav .next a { justify-content: flex-end; } .post-nav .chev { flex: none; font-size: 1.4em; color: inherit; line-height: 1; } .post-nav .t { text-align: center; } /* Pie chart of category breakdown (SVG with hoverable slices) */ .projects-pie-wrap { display: flex; justify-content: center; margin: 1.5rem 0; } .projects-pie { width: 380px; height: 290px; max-width: 100%; filter: drop-shadow(0 1px 4px rgba(0,0,0,.1)); } html[data-theme="dark"] .projects-pie { filter: drop-shadow(0 1px 6px rgba(0,0,0,.4)); } .projects-pie path, .projects-pie circle { cursor: default; transition: opacity 80ms; } .projects-pie path:hover, .projects-pie circle:hover { opacity: .85; } .pie-label { fill: var(--fg); font-size: 9px; font-weight: 600; dominant-baseline: central; pointer-events: none; } .pie-lead { stroke: var(--muted); stroke-width: 0.6; fill: none; } .chart-legend { display: flex; flex-wrap: wrap; gap: .5rem 1rem; margin-top: .8rem; font-size: .85em; color: var(--muted); } .chart-legend .legend-item { display: inline-flex; align-items: baseline; gap: .35rem; white-space: nowrap; } /* /ask-test chat UI */ .ask-form { display: flex; gap: .5rem; margin: 1rem 0 .5rem; } .ask-form input { flex: 1; padding: .6rem .8rem; font-size: 1rem; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); color: var(--fg); font-family: inherit; } .ask-form input:focus { outline: 2px solid var(--accent); outline-offset: 1px; } .ask-form button { padding: .6rem 1.2rem; font-size: 1rem; font-weight: 700; background: var(--accent); color: #fff; border: none; border-radius: 8px; cursor: pointer; font-family: inherit; } .ask-form button:disabled { opacity: .5; cursor: wait; } .ask-suggest { font-size: .85em; color: var(--muted); margin-bottom: 1.2rem; } .ask-out { font-size: 1rem; line-height: 1.65; padding: 1rem 1.2rem; background: var(--code-bg); border-radius: 10px; min-height: 3rem; display: none; } .ask-out.show { display: block; } .ask-out.loading::before { content: 'Thinking'; color: var(--muted); font-style: italic; } .ask-out.loading::after { content: '...'; color: var(--muted); font-style: italic; display: inline-block; width: 0; overflow: hidden; vertical-align: bottom; animation: think-dots 1.4s steps(4, end) infinite; } @keyframes think-dots { to { width: 1.6em; } } .ask-out.error { background: rgba(239,68,68,.1); color: #b91c1c; } .ask-meta { font-size: .75em; color: var(--muted); margin-top: .6rem; padding-top: .6rem; border-top: 1px dashed var(--border); } /* Mobile: stop the page from gaining horizontal scroll, without forcing the .wrap container to 100% (which broke the centered 42rem desktop layout). iOS Safari sometimes ignores overflow-x on body alone — set it on html too. */ html, body { overflow-x: hidden; max-width: 100%; } /* Belt-and-suspenders: clamp every chart container to its parent so an oversized SVG / inline-styled bar can't push the page wider on mobile. */ .projects-pie-wrap, .projects-pie, .projects-chart, .chart-bar, .projects-timeline, .tl-bars, .tl-axis, .projects-scoreboard { max-width: 100%; box-sizing: border-box; } /* Long project names / pasted URLs in notes were also a culprit. */ .proj-name, .proj-note, .scorecard-names { word-break: break-word; overflow-wrap: anywhere; } article img, article video, article iframe { max-width: 100%; height: auto; } article pre, article code { max-width: 100%; overflow-x: auto; word-wrap: break-word; } /* Cursor-following tooltip for SVG charts (pie slices have no ::after). */ .chart-tooltip { position: absolute; background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 1000; font-weight: 500; } /* Bar-segment instant tooltip (HTML so ::after works, like the timeline tiles). */ .bar-seg { position: relative; } .bar-seg::after { content: attr(data-tip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(-6px); background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 5; font-weight: 500; } .bar-seg:hover::after { opacity: 1; } /* /projects scoreboard + list */ .projects-scoreboard { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; margin: 1.75rem 0 2.25rem; align-items: stretch; } .scorecard { padding: 1.2rem 1.2rem 1.1rem; border-radius: 12px; border: 1px solid rgba(0,0,0,.06); display: flex; flex-direction: column; } .scorecard.good { background: #dcfce7; } /* pastel green */ .scorecard.made { background: #fef3c7; } /* pastel yellow */ .scorecard.failed { background: #fee2e2; } /* pastel red */ .scorecard.nonprofit { background: #ede9fe; } /* pastel purple */ .scorecard.newproj { background: #dbeafe; } /* pastel blue */ .scorecard.exited { background: #fce7f3; } /* pastel pink (success-exit) */ /* If there's an odd number of cards, let the last one span both columns. */ .scorecard:last-child:nth-child(odd) { grid-column: 1 / -1; } html[data-theme="dark"] .scorecard { border-color: rgba(255,255,255,.06); } html[data-theme="dark"] .scorecard.good { background: #102b1f; } html[data-theme="dark"] .scorecard.made { background: #2b2616; } html[data-theme="dark"] .scorecard.failed { background: #2b1818; } html[data-theme="dark"] .scorecard.nonprofit { background: #1f1a2e; } html[data-theme="dark"] .scorecard.newproj { background: #11202e; } html[data-theme="dark"] .scorecard.exited { background: #2b1424; } .scorecard-head { font-size: .72em; color: rgba(0,0,0,.6); text-transform: uppercase; letter-spacing: .08em; font-weight: 700; } html[data-theme="dark"] .scorecard-head { color: rgba(255,255,255,.65); } .scorecard-count { font-size: 2.6em; font-weight: 800; line-height: 1; margin: .35rem 0 .15rem; color: rgba(0,0,0,.85); display: flex; align-items: baseline; gap: .4rem; } html[data-theme="dark"] .scorecard-count { color: rgba(255,255,255,.95); } .scorecard-pct { font-size: .42em; font-weight: 500; color: rgba(0,0,0,.5); letter-spacing: .02em; } html[data-theme="dark"] .scorecard-pct { color: rgba(255,255,255,.55); } .scorecard-names { margin-top: .9rem; padding-top: .9rem; border-top: 1px dashed rgba(0,0,0,.1); display: flex; flex-wrap: wrap; gap: .4rem; } html[data-theme="dark"] .scorecard-names { border-top-color: rgba(255,255,255,.1); } .name-pill { display: inline-block; padding: .22em .7em; border-radius: 999px; background: rgba(255,255,255,.75); color: rgba(0,0,0,.85); font-size: .82em; line-height: 1.5; border: 1px solid rgba(0,0,0,.06); text-decoration: none; font-weight: 500; transition: background 80ms, color 80ms, border-color 80ms; } html[data-theme="dark"] .name-pill { background: rgba(255,255,255,.08); color: rgba(255,255,255,.92); border-color: rgba(255,255,255,.06); } a.name-pill:hover { background: rgba(0,0,0,.85); color: #fff; border-color: transparent; text-decoration: none; } html[data-theme="dark"] a.name-pill:hover { background: rgba(255,255,255,.9); color: #15171a; } @media (max-width: 640px) { .projects-scoreboard { grid-template-columns: 1fr; } } .projects-list { margin-top: 1.5rem; } .proj-year { font-weight: 700; font-size: 1.25em; margin: 1.6em 0 .6em; } .proj-entry { display: flex; gap: .55rem; align-items: baseline; padding: .3rem 0; } .proj-date { color: var(--muted); font-variant-numeric: tabular-nums; width: 4.5em; flex: none; font-size: .9em; } .proj-name { font-weight: 700; } .proj-name a { color: var(--fg); } .proj-status { color: var(--muted); font-size: .82em; margin-left: auto; flex: none; } .proj-post { font-size: .9em; margin: -.15em 0 .6em 0; } .proj-post a { color: var(--accent); font-weight: 600; } .proj-note { color: var(--quote); font-size: .92em; margin: .15em 0 .5em 0; line-height: 1.55; } .cat-dot { font-size: 1.1em; line-height: 1; flex: none; } .cat-dot.good { color: #16a34a; } .cat-dot.made { color: #d97706; } .cat-dot.failed { color: #ef4444; } .cat-dot.nonprofit { color: #8b5cf6; } .cat-dot.newproj { color: #2563eb; } .cat-dot.exited { color: #ec4899; } /* 100%-stacked bar visualising the same breakdown */ .projects-chart { margin: 0 0 2rem; } .chart-bar { display: flex; height: 40px; border-radius: 8px; overflow: hidden; border: 1px solid rgba(0,0,0,.06); } html[data-theme="dark"] .chart-bar { border-color: rgba(255,255,255,.06); } .bar-seg { display: flex; align-items: center; justify-content: center; font-size: .82em; font-weight: 700; color: #fff; min-width: 2px; transition: opacity 80ms, transform 80ms; cursor: pointer; } .bar-seg:hover { opacity: .85; } .bar-seg.dim { opacity: .25; } .bar-seg.active { transform: scaleY(1.08); box-shadow: inset 0 0 0 2px rgba(255,255,255,.6); } /* Click-to-filter (multi-select): timeline gets `filtering` + a `sel-` class per chosen category; only those categories' tiles stay visible. Click a legend item or bar segment; shift-click to combine several. */ .projects-timeline.filtering .tl-seg { display: none; } .projects-timeline.filtering.sel-good .tl-seg.good { display: block; } .projects-timeline.filtering.sel-made .tl-seg.made { display: block; } .projects-timeline.filtering.sel-failed .tl-seg.failed { display: block; } .projects-timeline.filtering.sel-nonprofit .tl-seg.nonprofit { display: block; } .projects-timeline.filtering.sel-newproj .tl-seg.newproj { display: block; } .projects-timeline.filtering.sel-exited .tl-seg.exited { display: block; } .bar-seg.good { background: #16a34a; } .bar-seg.made { background: #d97706; } .bar-seg.failed { background: #ef4444; } .bar-seg.nonprofit { background: #8b5cf6; } .bar-seg.newproj { background: #2563eb; } .bar-seg.exited { background: #ec4899; } .chart-legend { display: flex; flex-wrap: wrap; gap: .5rem 1rem; margin-top: .8rem; font-size: .85em; color: var(--muted); } .legend-item { display: inline-flex; align-items: center; gap: .35rem; cursor: pointer; transition: opacity .1s; } .chart-legend.has-active .legend-item { opacity: .4; } .chart-legend.has-active .legend-item.active { opacity: 1; } .chart-legend .legend-item.active strong { text-decoration: underline; } .chart-hint { font-size: .8em; color: var(--muted); opacity: .7; margin: .5rem 0 0; } .legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; box-shadow: inset 0 0 0 .5px rgba(0,0,0,.25); } .legend-dot.good { background: #16a34a; } .legend-dot.made { background: #d97706; } .legend-dot.failed { background: #ef4444; } .legend-dot.nonprofit { background: #8b5cf6; } .legend-dot.newproj { background: #2563eb; } .legend-dot.exited { background: #ec4899; } .legend-item strong { color: var(--fg); font-weight: 700; } /* Timeline (one column per year, stacked tiles per project) */ .projects-timeline { margin: 1.25rem 0 2rem; } .tl-controls { display: flex; gap: .8rem; align-items: center; margin: 0 0 .5rem; font-size: .85em; color: var(--muted); flex-wrap: wrap; } .tl-toggle { display: inline-flex; align-items: center; gap: .4em; cursor: pointer; user-select: none; } .tl-toggle input { cursor: pointer; margin: 0; } /* "Only show launches" hides every continuation tile (overrides filter rules too). */ .projects-timeline.launches-only .tl-seg:not(.tl-seg-launch) { display: none !important; } .tl-bars { display: flex; align-items: flex-end; gap: 1px; /* height set inline so PHP can scale to the busiest year */ border-bottom: 1px solid var(--border); padding: 0 0 1px; } .tl-col { flex: 1; display: flex; flex-direction: column-reverse; gap: 1px; min-width: 4px; height: 100%; justify-content: flex-start; } .tl-seg { flex: none; height: 4px; border-radius: 1px; display: block; position: relative; transition: filter 80ms; } /* Non-transforming hover so the child tooltip isn't stretched. */ .tl-seg:hover { filter: brightness(1.4) saturate(1.15); z-index: 2; box-shadow: 0 0 0 1px rgba(255,255,255,.4); } html[data-theme="dark"] .tl-seg:hover { box-shadow: 0 0 0 1px rgba(0,0,0,.4); } /* Instant tooltip on hover — native title has ~1s delay. */ .tl-seg::after { content: attr(data-tip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(-6px); background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 5; font-weight: 500; } .tl-seg:hover::after { opacity: 1; } .tl-seg.good { background: #16a34a; } .tl-seg.made { background: #d97706; } .tl-seg.failed { background: #ef4444; } .tl-seg.nonprofit { background: #8b5cf6; } .tl-seg.newproj { background: #2563eb; } .tl-seg.exited { background: #ec4899; } /* Revenue chart — same visual language as the timeline above it. */ .projects-revenue { margin: 1.25rem 0 2rem; } .rev-title { font-size: .85em; color: var(--muted); margin: 0 0 .5rem; } .rev-bars { display: flex; align-items: flex-end; gap: 1px; border-bottom: 1px solid var(--border); padding: 0 0 1px; } .rev-col { flex: 1; display: flex; flex-direction: column-reverse; gap: 0; min-width: 4px; height: 100%; justify-content: flex-start; } /* Faint inset outline keeps white/light segments (Merch, X) visible on light theme. */ .rev-seg { flex: none; display: block; border-radius: 1px; position: relative; transition: filter 80ms; box-shadow: inset 0 0 0 .5px rgba(0,0,0,.18); } html[data-theme="dark"] .rev-seg { box-shadow: inset 0 0 0 .5px rgba(255,255,255,.12); } .rev-seg:hover { filter: brightness(1.4) saturate(1.15); z-index: 2; box-shadow: 0 0 0 1px rgba(255,255,255,.4); } html[data-theme="dark"] .rev-seg:hover { box-shadow: 0 0 0 1px rgba(0,0,0,.4); } .rev-seg::after { content: attr(data-tip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(-6px); background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 5; font-weight: 500; } .rev-seg:hover::after { opacity: 1; } .tl-axis { display: flex; gap: 1px; font-size: .68em; color: var(--muted); margin-top: .4rem; } .tl-axis span { flex: 1; text-align: center; min-width: 4px; overflow: visible; white-space: nowrap; } /* When linked to from a pill, give the target row a subtle highlight + breathing room */ .proj-entry { scroll-margin-top: 1rem; transition: background 200ms; } .proj-entry:target { background: rgba(255,235,165,.35); border-radius: 6px; padding-left: .35rem; margin-left: -.35rem; } html[data-theme="dark"] .proj-entry:target { background: rgba(255,235,165,.08); } form.catch-emails { text-align: center; margin-top: 1.5rem; } /* Newsletter signup card on the front page, below the pinned box. */ .front-subscribe { margin: 1.5rem 0 0; padding: 1.25rem 1.25rem 1.5rem; border: 1px solid var(--border); border-radius: 8px; background: var(--code-bg); } /* Subscription-confirmed banner on top of the front page (/confirm). */ .confirm-banner { margin: 1rem 0 1.5rem; padding: 1rem 1.25rem; border: 2px solid var(--accent); border-radius: 8px; background: var(--code-bg); } .confirm-banner p { margin: .35em 0; } .front-subscribe p { margin: 0; text-align: center; color: var(--fg); } /* The lead line: inside the subscribe card on the blog, above it on the intro. */ .fs-lead { line-height: 1.45; text-wrap: balance; text-align: center; margin: 1.5rem 0 .75rem; color: var(--fg); } .fs-lead + .front-subscribe { margin-top: 0; } .front-subscribe .fs-note { max-width: 28rem; margin: .85rem auto 0; font-size: .8rem; color: var(--muted); line-height: 1.4; text-wrap: balance; } .front-subscribe form.catch-emails { margin-top: 1rem; margin-bottom: 0.5rem; } .catch-emails-text-box { outline:none; border:none; border-radius:6px; border-top-right-radius:0; border-bottom-right-radius:0; padding:12px; font-size:15px; vertical-align:middle; color:#3c484e; border-right:none; width:200px; box-shadow:0 0 0 1px var(--accent), 0 2px 4px 0 rgb(0 0 0 / 7%), 0 1px 1.5px 0 rgb(0 0 0 / 5%); } .catch-emails-button { cursor:pointer; background:var(--accent); appearance:none; color:#fff; padding:11px; font-weight:600; margin-left:0; font-size:15px; border-radius:6px; border-top-left-radius:0; border-bottom-left-radius:0; vertical-align:middle; border:1px solid var(--accent); z-index:1; position:relative; outline:1px solid var(--accent); width:130px; } .catch-emails-button:hover { background:none; color:var(--accent); border:1px solid var(--accent); } /* The intro keeps the chunkier 2px border it always had. */ #intro .catch-emails-button, #intro .catch-emails-button:hover { border-width:2px; } /* White on the accent measures 2.42:1 against the lighter dark-mode accent — well under the 4.5:1 AA wants for 15px/600 text. Dark text on the same blue is 7.41:1, so dark mode flips the label. */ html[data-theme="dark"] .catch-emails-button { color:#fff; } html[data-theme="dark"] .catch-emails-button:hover { color:var(--accent); } form.catch-emails .loading, form.catch-emails .error, form.catch-emails .success { display:none; } form.catch-emails.loading .not-subscribed, form.catch-emails.success .not-subscribed { display:none; } form.catch-emails.loading .loading { display:block; color:var(--muted); } form.catch-emails.error .error { display:block; color:#d33; margin-top:.5rem; } form.catch-emails.success .success { display:block; color:var(--accent); font-weight:600; } @media (max-width: 480px) { .catch-emails-text-box, .catch-emails-button { width:100%; margin:0 0 14px; display:block; border-radius:12px; } .catch-emails-button { margin:0; } } Subscribe
← all posts

My weird code commenting style based on HTML tags

4 May, 2015 · 1,279 views

So I know by now I do most things in programming in a weird and unconventional way, but somehow that has worked pretty well for me. My sites are definitely a bit more buggy than most, but I ship quite a bit faster too. You can’t have it all.

One thing I never was able to learn properly was commenting my code. The way people usually comment code is this:

This was taken straight from PHP The Right Way. The thing I struggle with is that the deeper you get with indentation, the more of a mess this becomes. What if you’re deep in two foreach loops, how do you have any idea which code part starts and ends where? The issue is that the commenting doesn’t segment the code in any way. You can’t see the end of a piece of code.

You can use functions to summarize code in to one line. That solves a lot of things. But making every little snippet of code into a function can slow you down too.

What if there was a middle ground?

I got inspired by HTML, its code is always very clear because you see when a tag starts and ends. It’s pretty clear. So here’s how I comment based on that:

I use this style of commenting in PHP, JavaScript, Obj-C and even Shell scripts and it’s saved me countless of time quickly figuring out what part of a file I’m actually editing and what it does.

Even more fun is that if you use Sublime Text, you can simply fold down the entire parts between tags like this:

It’s probably wrong in the grand scheme of coding laws written up by the board of bearded men who roam around Hacker News. But that’s fine. I don’t have a beard.

P.S. I'm on 𝕏 too if you'd like to follow more of my stories. And I wrote a book called MAKE about building startups without funding. See a list of my stories or contact me.

Never miss a post: 182,448 people read my posts in full by email, before it spreads anywhere else

Subscribing you...
Subscribed! Check your inbox to confirm your email.

Or subscribe on Telegram →


Related posts