/* measured — fede.kamelhar.net
   A notebook, not a landing page: the index is the page. No hero, no cover
   above the fold. Metadata is monospace; everything else is Inter. */

:root{
  --col:820px;          /* the page column */
  --measure:680px;      /* reading width inside an article */
  --wide:900px;         /* figures break out to here */
  --paper:#FAF9F5; --band:#F1EFE8; --ink:#1A1917; --body:#3C3A35;
  /* Secondary ink. These carry dates, kickers, descriptions, nav and footer --
     small text, often monospace, which is where a light grey stops being
     restraint and becomes a squint. Both were below WCAG AA on this paper
     (#8A857A was 3.49:1, #B4AEA2 was 2.09:1); they are now 5.43:1 and 4.67:1,
     and keep the same order so the hierarchy still reads. */
  --muted:#6B6659; --faint:#767064; --rule:#E3E0D7; --accent:#0F6B78; --teal:#12707F;
  /* If a font is chosen in Ghost admin it wins; otherwise the design's own
     stack does. The serif is deliberate and has no Ghost setting, so it is
     fixed. */
  /* Claude's own faces are Styrene (sans) and Tiempos/Copernicus (serif), both
     licensed from Klim and not redistributable, so these are the closest free
     equivalents: Hanken Grotesk for Styrene's humanist grotesque, Newsreader for
     the serif. If those licences are ever bought, the names go first in these two
     stacks and nothing else changes. A font chosen in Ghost admin still wins. */
  --sans:var(--gh-font-body,'Hanken Grotesk','Styrene A',system-ui,-apple-system,'Segoe UI',sans-serif);
  --display:var(--gh-font-heading,'Newsreader','Tiempos Headline',Georgia,serif);
  --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --serif:'Newsreader','Tiempos Text',Georgia,serif;
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;color-scheme:light}
body{margin:0;background:var(--paper);color:var(--body);
  font:400 17px/1.72 var(--sans);-webkit-font-smoothing:antialiased}
img{max-width:100%;height:auto;display:block}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline;text-underline-offset:3px}
.col{width:100%;max-width:var(--col);margin-inline:auto;padding-inline:24px}
.mono{font-family:var(--mono)}

/* header ---------------------------------------------------------------- */
.bar{display:flex;align-items:center;justify-content:space-between;gap:24px;
  padding-block:22px;border-bottom:1px solid var(--rule)}
.brand{font-family:var(--mono);font-size:13px;font-weight:500;color:var(--ink);letter-spacing:.02em}
.brand:hover{color:var(--accent);text-decoration:none}
.brand-mark{height:20px;width:auto}
.nav{display:flex;gap:22px;align-items:center}
/* Ghost's own navigation markup is a <ul>; if it is ever used instead of the
   theme's, it must not arrive with list bullets. */
.nav ul,.foot-links ul{list-style:none;display:flex;gap:inherit;margin:0;padding:0}
.nav li,.foot-links li{margin:0}
.nav a{font-family:var(--mono);font-size:13px;color:var(--muted);
  display:inline-flex;align-items:center;min-height:32px}
.nav a[aria-current],.nav a:hover{color:var(--ink);text-decoration:none}
/* the search button: the nav's ink and hit area, a glyph instead of a word. A
   <button> brings the browser's chrome with it, so that is taken off here; the
   focus ring is put back on purpose, in the accent, for the keyboard only. */
.search{appearance:none;background:none;border:0;padding:0;margin:0;font:inherit;
  color:var(--muted);cursor:pointer;display:inline-flex;align-items:center;
  justify-content:center;min-width:32px;min-height:32px;border-radius:4px}
.search:hover{color:var(--ink)}
.search:focus-visible,.nav a:focus-visible,.brand:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.search .ico{opacity:1}

/* section labels -------------------------------------------------------- */
.label{display:flex;align-items:center;justify-content:space-between;
  padding-bottom:10px;border-bottom:1px solid var(--rule);
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.label i{font-style:normal;color:var(--faint)}

/* home ------------------------------------------------------------------ */

.rows{list-style:none;margin:0;padding:0}
.rows li{border-bottom:1px solid var(--rule)}
.post{display:grid;grid-template-columns:70px 1fr 168px;gap:24px;align-items:start;
  padding-block:18px;color:inherit}
.post:hover{text-decoration:none}
.post .when{font-family:var(--mono);font-size:12.5px;color:var(--muted);padding-top:5px}
.post .says{font-size:14.5px;line-height:1.5;color:var(--muted);margin:5px 0 0;max-width:46em}
/* the cover, small enough to stay an index rather than become a gallery */
.post .thumb{width:168px;height:88px;object-fit:cover;border-radius:5px;
  border:1px solid var(--rule);background:var(--band);
  transition:border-color .15s ease}
.post:hover .thumb{border-color:var(--accent)}
.post h2{font-size:18px;font-weight:600;line-height:1.38;color:var(--ink);margin:0 0 6px;
  letter-spacing:-.005em}
.post:hover h2{color:var(--accent)}
.post .tags{font-family:var(--mono);font-size:11.5px;color:var(--muted);margin:0}
.section{padding-bottom:44px}
.section.top{padding-top:34px}

.work{display:grid;grid-template-columns:170px 1fr auto;gap:22px;align-items:center;
  padding-block:14px}
.work .name{font-size:15px;font-weight:500}
.work .name a{color:var(--accent)}
.work .what{font-size:14.5px;color:var(--muted)}
/* The right-hand label names where the row goes -- "github", "arXiv". It read as
   a destination and was plain text, so it was the one part of the row that looked
   like a link and was not. It is an <a> now, to the same place as the name. */
.work .go{font-family:var(--mono);font-size:12px;white-space:nowrap;
  justify-self:end;text-align:right}
.work .go a{color:var(--faint);text-decoration:none;display:inline-flex;
  align-items:center;min-height:28px}
.work .go a:hover{color:var(--accent);text-decoration:underline}

/* article --------------------------------------------------------------- */
.head{padding-block:44px 30px;border-bottom:1px solid var(--rule)}

/* the cover: a full-bleed banner above the title, not a figure inside the
   column. It breaks out of .col on purpose - a "cover" that respects the
   text margins is just a large image, not a masthead. Normal document
   flow, no position:sticky - it scrolls away like any other element, which
   is the whole point: readers see it once, then it is gone. */
.cover{width:100%;margin:0;background:var(--ink);overflow:hidden;line-height:0}
.cover img{width:100%;height:auto;display:block;max-height:420px;object-fit:cover}
@media (min-width:1400px){.cover img{max-height:520px}}
.kicker{font-family:var(--mono);font-size:12px;letter-spacing:.04em;color:var(--teal);margin:0 0 16px}
.title{font-family:var(--display);font-size:40px;font-weight:500;line-height:1.16;color:var(--ink);margin:0 0 16px;
  letter-spacing:-.01em;text-wrap:balance}
.sub{font-size:18px;line-height:1.52;color:var(--muted);margin:0;max-width:700px}

.prose{padding-block:36px 28px}
.prose>*{width:100%;max-width:var(--measure);margin-inline:auto;padding-inline:24px}
.prose>p{margin:0 auto 22px}
.prose>h2{font-size:21px;font-weight:600;color:var(--ink);letter-spacing:-.01em;
  margin:36px auto 12px;padding-top:22px;border-top:1px solid var(--rule)}
.prose>h3{font-size:17px;font-weight:600;color:var(--ink);margin:28px auto 8px}
.prose>ul,.prose>ol{margin:0 auto 22px;padding-left:42px}
.prose li{margin-bottom:6px}
.prose strong{color:var(--ink);font-weight:600}
.prose>hr{border:0;border-top:1px solid var(--rule);margin:32px auto}

.prose>figure{max-width:var(--wide);margin:34px auto}
.prose>figure img{border:1px solid var(--rule);border-radius:6px;background:#fff;margin-inline:auto}
.prose figcaption{font-size:14px;line-height:1.52;color:var(--muted);text-align:center;
  margin:11px auto 0;max-width:var(--measure)}
.prose figure.mark img{max-width:170px;border:0;background:none}

.prose>pre{max-width:var(--measure);background:var(--band);border:1px solid var(--rule);
  border-radius:5px;padding:13px 16px;overflow-x:auto;margin:22px auto;
  font-family:var(--mono);font-size:13.5px;line-height:1.7;color:var(--ink)}
.prose pre code{background:none;border:0;padding:0;font-size:inherit;color:inherit}
.prose :not(pre)>code{font-family:var(--mono);font-size:.88em;background:var(--band);
  border:1px solid var(--rule);border-radius:3px;padding:.1em .34em;color:var(--accent)}

.prose>table{max-width:var(--wide);width:100%;border-collapse:collapse;margin:26px auto;
  font-size:14.5px;line-height:1.5;display:block;overflow-x:auto}
.prose th{text-align:left;font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);font-weight:500;padding:10px 14px;
  border-bottom:1px solid var(--ink)}
.prose td{padding:13px 14px;border-bottom:1px solid var(--rule);vertical-align:top}
.prose td:first-child{color:var(--ink);font-weight:500}

.prose>blockquote{max-width:var(--measure);border-left:2px solid var(--accent);
  padding:2px 0 2px 18px;margin:22px auto;font-size:16px;color:var(--body)}
.prose>blockquote p{margin:0 0 6px}
.prose>blockquote strong{display:block;color:var(--ink)}

.posttags{padding-bottom:36px;display:flex;flex-wrap:wrap;gap:8px}
.posttags span{font-family:var(--mono);font-size:11.5px;color:var(--muted);
  border:1px solid var(--rule);border-radius:100px;padding:4px 10px}

/* pages (about) ---------------------------------------------------------
   A page is one column wide: no reading-measure clamp, so its table and its
   portrait share the same axis as everything else on the site. */
.page{padding-block:52px 24px}
.page.has-portrait{display:grid;grid-template-columns:1fr 104px;gap:34px;align-items:start}
.page .portrait{width:104px;height:104px;border-radius:50%;object-fit:cover;
  border:1px solid var(--rule);grid-column:2;grid-row:1}
.page-body{min-width:0}
.page-body>h1{font-size:27px;font-weight:600;color:var(--ink);margin:0 0 18px;letter-spacing:-.01em}
.page-body>h2{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);font-weight:500;margin:44px 0 20px;padding-bottom:10px;
  border-bottom:1px solid var(--rule)}
.page-body>p strong{color:var(--ink);font-weight:600}
.page-body>p{font-size:16.5px;line-height:1.7;margin:0 0 18px;max-width:640px}
.page-body>p:last-child{font-size:14px;color:var(--faint);margin:26px 0 0}
/* A list in a page body. The About page's upstream work is a list rather than a
   table because it has a real header (project, contribution, count) and this
   page's tables deliberately hide theirs -- they are name/value pairs, and a
   header above two columns of the same thing is noise. A list needs none. */
.page-body>ul{margin:0 0 18px;padding-left:20px;max-width:640px}
.page-body>ul li{font-size:15.5px;line-height:1.65;margin-bottom:10px}
.page-body>ul strong{font-weight:600}
.page-body>table{width:100%;border-collapse:collapse;margin:0;font-size:15px}
.page-body>table th{display:none}
.page-body>table td{padding:13px 0;border-bottom:1px solid var(--rule);vertical-align:middle}
.page-body>table td:first-child{width:180px;font-weight:500}
.page-body>table td:last-child{font-family:var(--mono);font-size:12.5px;color:var(--muted)}

/* footer ---------------------------------------------------------------- */
.foot{padding-block:56px 56px}
.foot-in{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  padding-top:18px;border-top:1px solid var(--rule);
  font-family:var(--mono);font-size:12px;color:var(--faint)}
.foot-links{display:flex;gap:20px}

@media (max-width:760px){
  body{font-size:16px}
  /* the masthead on a phone: a full name in monospace and two nav items do not
     fit 320px at desktop sizes, and the bar was the one thing the old mobile
     block never touched. Smaller type and a tighter gap rather than a burger --
     two links do not earn a menu. */
  .bar{gap:12px;padding-block:18px}
  .brand{font-size:12px;letter-spacing:.01em}
  .brand-mark{height:18px}
  .nav{gap:16px}
  .nav a{font-size:12px}
  /* a glyph alone is a small thing to hit with a thumb: 40px square, pulled back
     by the extra so the bar's right edge still lines up with the column */
  .search{min-width:40px;min-height:40px;margin-right:-8px}
  .post{grid-template-columns:1fr;gap:10px}
  .post .thumb{width:100%;height:auto;aspect-ratio:1.9}
  .work{grid-template-columns:1fr;gap:4px}
  .who{grid-template-columns:1fr}
  .section.top{padding-top:32px}
  .head{padding-block:32px 22px}
  .title{font-size:30px}
}

/* code colours */
pre { line-height: 125%; }
td.linenos .normal { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.prose pre code .hll { background-color: #ffffcc }
.prose pre code { background: #f0f0f0; }
.prose pre code .c { color: #60a0b0; font-style: italic } /* Comment */
.prose pre code .err { border: 1px solid #FF0000 } /* Error */
.prose pre code .k { color: #007020; font-weight: bold } /* Keyword */
.prose pre code .o { color: #666666 } /* Operator */
.prose pre code .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */
.prose pre code .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
.prose pre code .cp { color: #007020 } /* Comment.Preproc */
.prose pre code .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */
.prose pre code .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
.prose pre code .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
.prose pre code .gd { color: #A00000 } /* Generic.Deleted */
.prose pre code .ge { font-style: italic } /* Generic.Emph */
.prose pre code .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.prose pre code .gr { color: #FF0000 } /* Generic.Error */
.prose pre code .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.prose pre code .gi { color: #00A000 } /* Generic.Inserted */
.prose pre code .go { color: #888888 } /* Generic.Output */
.prose pre code .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.prose pre code .gs { font-weight: bold } /* Generic.Strong */
.prose pre code .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.prose pre code .gt { color: #0044DD } /* Generic.Traceback */
.prose pre code .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.prose pre code .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.prose pre code .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.prose pre code .kp { color: #007020 } /* Keyword.Pseudo */
.prose pre code .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.prose pre code .kt { color: #902000 } /* Keyword.Type */
.prose pre code .m { color: #40a070 } /* Literal.Number */
.prose pre code .s { color: #4070a0 } /* Literal.String */
.prose pre code .na { color: #4070a0 } /* Name.Attribute */
.prose pre code .nb { color: #007020 } /* Name.Builtin */
.prose pre code .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.prose pre code .no { color: #60add5 } /* Name.Constant */
.prose pre code .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.prose pre code .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.prose pre code .ne { color: #007020 } /* Name.Exception */
.prose pre code .nf { color: #06287e } /* Name.Function */
.prose pre code .nl { color: #002070; font-weight: bold } /* Name.Label */
.prose pre code .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.prose pre code .nt { color: #062873; font-weight: bold } /* Name.Tag */
.prose pre code .nv { color: #bb60d5 } /* Name.Variable */
.prose pre code .ow { color: #007020; font-weight: bold } /* Operator.Word */
.prose pre code .w { color: #bbbbbb } /* Text.Whitespace */
.prose pre code .mb { color: #40a070 } /* Literal.Number.Bin */
.prose pre code .mf { color: #40a070 } /* Literal.Number.Float */
.prose pre code .mh { color: #40a070 } /* Literal.Number.Hex */
.prose pre code .mi { color: #40a070 } /* Literal.Number.Integer */
.prose pre code .mo { color: #40a070 } /* Literal.Number.Oct */
.prose pre code .sa { color: #4070a0 } /* Literal.String.Affix */
.prose pre code .sb { color: #4070a0 } /* Literal.String.Backtick */
.prose pre code .sc { color: #4070a0 } /* Literal.String.Char */
.prose pre code .dl { color: #4070a0 } /* Literal.String.Delimiter */
.prose pre code .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.prose pre code .s2 { color: #4070a0 } /* Literal.String.Double */
.prose pre code .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.prose pre code .sh { color: #4070a0 } /* Literal.String.Heredoc */
.prose pre code .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.prose pre code .sx { color: #c65d09 } /* Literal.String.Other */
.prose pre code .sr { color: #235388 } /* Literal.String.Regex */
.prose pre code .s1 { color: #4070a0 } /* Literal.String.Single */
.prose pre code .ss { color: #517918 } /* Literal.String.Symbol */
.prose pre code .bp { color: #007020 } /* Name.Builtin.Pseudo */
.prose pre code .fm { color: #06287e } /* Name.Function.Magic */
.prose pre code .vc { color: #bb60d5 } /* Name.Variable.Class */
.prose pre code .vg { color: #bb60d5 } /* Name.Variable.Global */
.prose pre code .vi { color: #bb60d5 } /* Name.Variable.Instance */
.prose pre code .vm { color: #bb60d5 } /* Name.Variable.Magic */
.prose pre code .il { color: #40a070 } /* Literal.Number.Integer.Long */

/* ---------------------------------------------------------------------
   Ghost specifics. The design above is unchanged; these only teach it
   about the markup Ghost emits that the previous renderer did not:
   Koenig cards, the figure/figcaption pairs they wrap images in, and
   the members/portal furniture we do not use.
   --------------------------------------------------------------------- */

/* Koenig image cards behave like the figures the design already styles */
.prose .kg-card{max-width:var(--wide);margin:34px auto}
.prose .kg-image-card img,.prose .kg-image{border:1px solid var(--rule);border-radius:6px;
  background:#fff;margin-inline:auto}
.prose .kg-card figcaption,.prose figcaption{font-size:14px;line-height:1.52;color:var(--muted);
  text-align:center;margin:11px auto 0;max-width:var(--measure)}
.prose .kg-width-wide{max-width:var(--wide)}
.prose .kg-width-full{max-width:none}

/* Koenig code cards */
.prose .kg-code-card pre{margin:0}

/* callouts / bookmark cards keep the quiet house style */
.prose .kg-callout-card{max-width:var(--measure);margin:22px auto;padding:14px 18px;
  border-left:2px solid var(--accent);background:var(--band);border-radius:0 5px 5px 0}
.prose .kg-callout-emoji{margin-right:10px}

/* Ghost injects portal/members markup we have no use for on a public,
   account-free blog */
.gh-portal-triggerbtn-iframe,#ghost-portal-root{display:none!important}

/* the logo marks in the post body stay small, as before */
.prose img[src*="nvidia_n"],.prose img[src*="vllm_n"],.prose img[src*="qwen_n"]{
  max-width:170px;border:0;background:none}

/* footer glyphs: 14px, currentColor, riding the baseline. gap rather than a
   margin so a link with no glyph is spaced identically to one with. */
.foot-links a{display:inline-flex;align-items:center;gap:6px}
.ico{flex:0 0 auto;opacity:.75}
.foot-links a:hover .ico{opacity:1}

/* Below ~360px the name and the nav stop sharing a line: the nav drops under it,
   still left-aligned to the same column edge. Nothing is hidden or collapsed. */
@media (max-width:360px){
  .bar{flex-wrap:wrap;row-gap:6px}
  .nav{width:100%}
}

/* pagination -------------------------------------------------------------
   Ghost's helper always renders, even when there is one page of one post, and
   its default markup is untouched by everything above -- which is how "Page 1
   of 1" ended up mid-page in 17px sans. Treated as a section footer, and
   hidden when there is only one page. */
.pagination{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding-block:18px;font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--faint)}
.pagination:has(.page-number:only-child){display:none}
.pagination a{color:var(--muted)}
.pagination a:hover{color:var(--ink);text-decoration:none}

/* phones ------------------------------------------------------------------ */
@media (max-width:760px){
  /* the row thumbnail is a wide banner carrying a headline; at phone width it
     crops mid-word and says less than nothing. The title is right above it. */
  .post .thumb{display:none}
  /* footer links get the same hit area as the nav */
  .foot-links a{min-height:32px}
  /* An article's tables are comparisons and measurements: concurrency against
     throughput, flag against reason. Stacking those and dropping the header row
     (which is what this used to do) leaves a column of values with nothing
     saying which column each came from -- fine for the About page's name/value
     pairs, wrong for a benchmark. So they scroll sideways with their headers
     intact, and -webkit-overflow-scrolling keeps that from feeling stuck.
     The row stays whole, which is the thing being read. */
  .prose>table{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;
    font-size:14px;white-space:nowrap}
  .prose>table td,.prose>table th{white-space:normal;min-width:110px}
  .prose>table td:first-child,.prose>table th:first-child{min-width:130px}
}

/* the slogan ------------------------------------------------------------- */
/* The only sentence above the rule. It had a standfirst under it, in body
   type -- except .slogan p (0,1,1) outranks .blurb (0,1,0), so the standfirst
   rendered at this size too and the top of the page was two display lines
   saying the same thing twice. One line is what was meant; the Work list
   below carries the standing the second line was reaching for. */
.slogan{padding-block:46px 0}
.slogan p{font-family:var(--serif);font-size:30px;line-height:1.18;color:var(--ink);
  margin:0;max-width:620px;letter-spacing:-.01em;text-wrap:balance}
@media (max-width:760px){
  .slogan{padding-block:30px 0}
  .slogan p{font-size:22px;line-height:1.24}
}

/* The standfirst, two sentences under the serif line.
   .slogan .standfirst is (0,2,0) and .slogan p is (0,1,1), so this wins on
   specificity rather than on source order -- the previous standfirst was a
   .blurb at (0,1,0), lost every property to the rule above it and rendered at
   30px in the serif. Each property .slogan p sets has to be answered here, or
   it inherits: the face, the size, the colour, the leading, the tracking and
   the balance. */
.slogan .standfirst{font-family:var(--sans);font-size:16.5px;line-height:1.6;
  color:var(--muted);margin:16px 0 0;max-width:640px;letter-spacing:0;
  text-wrap:pretty}
@media (max-width:760px){
  .slogan .standfirst{font-size:15.5px;line-height:1.55;margin-top:12px}
}

/* tap targets ------------------------------------------------------------
   WCAG 2.5.8 asks for 24px; a 20px line of text is a link you miss on a phone.
   Height comes from the hit area, not from the type size, which stays as
   designed. Applied everywhere rather than under a media query: a 32px target
   costs a mouse nothing. */
/* Height from padding, not from inline-flex: a flex line will not break, so the
   full name became one unwrappable 200px item and the masthead overflowed 320px.
   Padding gives the same 32px hit area and lets the text wrap. */
.brand{padding-block:6px}
.work .name a,.page-body>table td a{display:inline-flex;align-items:center;min-height:28px}

/* Elsewhere ---------------------------------------------------------------
   The About page's link table and the Work list on the index get a mark per
   destination. Keyed off the href rather than written into the markup: the
   content stays a plain table of links, and a row pointing somewhere new
   simply has no mark until this file learns about it -- never a broken image
   or a stray box. One selector list serves both places, so a mark added for
   one is the other's too.

   The glyph is a mask filled with currentColor, so it takes the link's colour
   and its hover state for free. */
.page-body>table td:first-child a,.work .name a{display:inline-flex;align-items:center;gap:8px;min-height:28px}
.page-body>table td:first-child a[href*="github.com"]::before,
.work .name a[href*="github.com"]::before,
.page-body>table td:first-child a[href*="linkedin.com"]::before,
.work .name a[href*="linkedin.com"]::before,
.page-body>table td:first-child a[href*="x.com"]::before,
.work .name a[href*="x.com"]::before,
.page-body>table td:first-child a[href*="tulipagents.ai"]::before,
.work .name a[href*="tulipagents.ai"]::before,
.page-body>table td:first-child a[href*="arxiv.org"]::before,
.work .name a[href*="arxiv.org"]::before,
.page-body>table td:first-child a[href*="oracle.com"]::before ,.work .name a[href*="oracle.com"]::before {
  content:"";width:14px;height:14px;flex:0 0 auto;background:currentColor;opacity:.75;
  -webkit-mask:var(--ico) center/contain no-repeat;mask:var(--ico) center/contain no-repeat;
}
.page-body>table td:first-child a[href*="github.com"],.work .name a[href*="github.com"]{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M8%200C3.58%200%200%203.58%200%208c0%203.54%202.29%206.53%205.47%207.59.4.07.55-.17.55-.38%200-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01%201.08.58%201.23.82.72%201.21%201.87.87%202.33.66.07-.52.28-.87.51-1.07-1.78-.2-2.91-.88-2.91-2.84%200-.56.2-1.02.53-1.38-.05-.13-.23-.66.05-1.37%200%200%20.43-.14%201.41.53a4.8%204.8%200%200%201%202.6%200c.98-.67%201.41-.53%201.41-.53.28.71.1%201.24.05%201.37.33.36.53.82.53%201.38%200%201.97-1.14%202.64-2.92%202.84.3.26.56.76.56%201.54%200%201.11-.01%202-.01%202.27%200%20.21.15.46.55.38A7.99%207.99%200%200%200%2016%208c0-4.42-3.58-8-8-8Z'/%3E%3C/svg%3E")}
.page-body>table td:first-child a[href*="linkedin.com"],.work .name a[href*="linkedin.com"]{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M3.6%2016H.3V5.3h3.3V16ZM1.9%203.9A1.9%201.9%200%201%201%201.9.1a1.9%201.9%200%200%201%200%203.8ZM16%2016h-3.3v-5.6c0-1.34-.48-2.25-1.68-2.25-.92%200-1.46.62-1.7%201.21-.09.21-.11.51-.11.8V16H5.9s.04-9.7%200-10.7h3.3v1.51c.44-.68%201.22-1.65%202.98-1.65%202.18%200%203.82%201.42%203.82%204.48V16Z'/%3E%3C/svg%3E")}
.page-body>table td:first-child a[href*="x.com"],.work .name a[href*="x.com"]{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M18.244%202.25h3.308l-7.227%208.26%208.502%2011.24H16.17l-5.214-6.817L4.99%2021.75H1.68l7.73-8.835L1.254%202.25H8.08l4.713%206.231zm-1.161%2017.52h1.833L7.084%204.126H5.117z'/%3E%3C/svg%3E")}
.page-body>table td:first-child a[href*="tulipagents.ai"],.work .name a[href*="tulipagents.ai"]{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M8%201.2c1.1%201.3%201.7%202.6%201.7%204v.3c.9-.8%201.9-1.2%203-1.3-.2%202.6-1.2%204.3-3%205.1-.5.2-1%20.35-1.4.4V15h-.6v-5.3c-.45-.05-.9-.2-1.4-.4-1.8-.8-2.8-2.5-3-5.1%201.1.1%202.1.5%203%201.3v-.3c0-1.4.6-2.7%201.7-4Z'/%3E%3C/svg%3E")}
.page-body>table td:first-child a[href*="arxiv.org"],.work .name a[href*="arxiv.org"]{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M3%201h7l3.5%203.5V15H3V1Zm6.5.9V5H13L9.5%201.9ZM5%207.5h6v.8H5v-.8Zm0%202.3h6v.8H5v-.8Zm0%202.3h4v.8H5v-.8Z'/%3E%3C/svg%3E")}
.page-body>table td:first-child a[href*="oracle.com"],.work .name a[href*="oracle.com"]{--ico:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M5%204h6a4%204%200%200%201%200%208H5a4%204%200%200%201%200-8Zm0%201.6a2.4%202.4%200%200%200%200%204.8h6a2.4%202.4%200%200%200%200-4.8H5Z'/%3E%3C/svg%3E")}
.page-body>table td:first-child a:hover::before,.work .name a:hover::before{opacity:1}

@media (max-width:760px){
  /* Elsewhere on a phone: the 180px first column left the descriptions three words
     wide. Label over description, one pair per row -- the same stacking the post's
     reference tables get. */
  .page-body>table td{display:block}
  .page-body>table td:first-child{width:auto;margin-bottom:2px}
  .page-body>table td:last-child{padding-top:0}
  .page-body>table tr{display:block;padding-block:12px;border-bottom:1px solid var(--rule)}
  .page-body>table td{border-bottom:0;padding:0}
  /* the portrait leads, then the text: a 104px circle beside a 40-character
     measure is not a layout */
  .page.has-portrait{grid-template-columns:1fr;gap:20px}
  .page .portrait{grid-column:1;grid-row:1;width:84px;height:84px}
}

/* the Tulip mark is a colour logo: a background image, with the mask switched off
   so it is not flattened to the link's ink */
.page-body>table td:first-child a[href*="tulipagents.ai"]::before,.work .name a[href*="tulipagents.ai"]::before{
  -webkit-mask:none;mask:none;background:url("../img/tulip-mark-pink.png") center/contain no-repeat;opacity:1}
.ico-img{display:block;border-radius:2px}

/* the footer on a narrow phone: four links with marks do not fit 320px on one
   line, and the row was not allowed to wrap, so the page scrolled sideways. */
.foot-links{flex-wrap:wrap;row-gap:4px}
@media (max-width:420px){
  .foot-in{flex-direction:column;align-items:flex-start;gap:8px}
}

}
