/* @robertblust/design — page.css, assembled from the shared blocks: reset v2 · header v14 ·
   title v1 · footer v1 · principles v1 · team v1 · surfaces v1.
   Editing this file in a site does nothing: the next npm run design overwrites it. */

*{box-sizing:border-box; margin:0; padding:0}
body{
  font-family:"Instrument Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
  background:var(--ground); color:var(--ink); line-height:1.5; min-height:100vh;
  background-image:var(--sky); background-repeat:no-repeat;
  -webkit-font-smoothing:antialiased;
  display:flex; flex-direction:column;
}
.mono{font-family:"Plex Mono", ui-monospace, "SF Mono", Menlo, monospace}
a{color:inherit}
/* The gutter is proportional until it has enough, and then it stops. `box-sizing` is
   border-box here, so the padding comes out of the max-width rather than sitting outside it:
   with a bare `7vw` the column got narrower the wider the screen got — 1001px at 1280,
   906 at 1960, 822 at 2560 — and never reached 1180 at any width at all. It peaked at
   1015px on a 1180px viewport and shrank in both directions from there.
   A page that narrows as its window widens is wrong on its own, and it broke the header a
   second time on a large screen: measured, the German nav row needs 1000px, and above 2000
   the column no longer had it. The cap is 80px because that is where `7vw` lands at 1143px,
   so every width below the widest laptop is unchanged to the pixel and only the screens
   where this was broken move. */
.shell{width:100%; max-width:1180px; margin:0 auto; padding:0 min(7vw, 80px)}

/* `align-items:center`, not the default `stretch`: a stretched link is a box the height of
   the whole row with its text at the top, which put the words above the language control
   beside them. Centered, each box is its own height and one line runs through every text. */
nav{display:flex; align-items:center; gap:1.9rem; font-size:.76rem; font-weight:500;
    letter-spacing:.14em; text-transform:uppercase; position:relative}
.navlinks{display:flex; align-items:center; gap:1.9rem}
/* Hidden until the row runs out of width; the media query at the end of this sheet
   is the only place it appears. The two icons swap on aria-expanded, the way the
   deck's play button swaps its own. */
.burger{display:none; align-items:center; justify-content:center; width:40px; height:40px;
        background:none; border:1px solid var(--rule); border-radius:8px;
        color:var(--dim); cursor:pointer; padding:0;
        transition:color .15s ease, border-color .15s ease}
.burger:hover{color:var(--ink); border-color:var(--c-mid)}
.burger svg{width:18px; height:18px; fill:none; stroke:currentColor;
            stroke-width:1.7; stroke-linecap:round}
.burger .ix{display:none}
.burger[aria-expanded="true"]{color:var(--c-mid); border-color:var(--c-mid)}
.burger[aria-expanded="true"] .ibars{display:none}
.burger[aria-expanded="true"] .ix{display:block}
nav a{color:var(--dim); text-decoration:none; padding:.2rem 0;
      border-top:1px solid transparent; border-bottom:1px solid transparent}
/* Hover is an underline and nothing else: `border-bottom-color`, not `border-color`,
   because the box now has a transparent border on both edges to keep its text centered,
   and `border-color` painted a line above the word as well as under it.
   The current page is not underlined — it is brighter. A page marks where you are with
   a different weight of ink; the underline is what follows the pointer. When both used
   the same line, the selected item read as permanently hovered. */
nav a:hover, nav a:focus-visible{border-bottom-color:var(--c-mid)}
/* the bar is the same component on both pages, so this page says which one you are on
   rather than dropping the item and leaving the header subtly different */
nav a[aria-current="page"]{color:var(--c-firm)}
/* The segmented control the decks put in their transport, at nav scale. Two real buttons
   in one bordered box, the pressed one filled — someone who has used the deck already
   knows what it is. It replaces one button with two clickable spans inside it, which said
   one thing to a pointer and another to a screen reader. */
.seg{display:inline-flex; border:1px solid var(--rule); border-radius:8px; overflow:hidden;
     flex:0 0 auto}
.seg button{font:inherit; letter-spacing:inherit; text-transform:inherit; background:none;
            border:0; cursor:pointer; padding:.26rem .5rem; color:var(--dim);
            transition:color .15s ease, background-color .15s ease}
.seg button:hover{color:var(--ink)}
.seg button[aria-pressed="true"]{color:var(--c-mid); background:var(--press); font-weight:600}
.seg button:focus-visible{outline:2px solid var(--c-mid); outline-offset:-2px}
/* The theme control is a .seg like the language one, so it inherits the border, the radius
   and the pressed treatment. Only the icons differ: 14px square, drawn with currentColor so
   the pressed state colors them without a second rule. */
/* The language control's buttons are as tall as the text line box inside them; these hold a
   14px icon and came out 4px shorter, so the two controls sat at different heights in a row
   whose whole point is one baseline. One line box is the floor here too, which keeps the
   language control the base rather than copying a number off it: `em` first for anything
   without `lh`, both resolving to the same 18.24px today. The padding is added back because
   `box-sizing` is `border-box` here — a bare line box is smaller than the button already is
   and would bind on nothing, which is exactly how the first attempt at this failed. */
.seg.theme button{display:grid; place-items:center; padding:.26rem .48rem;
                  min-height:calc(1.5em + .52rem); min-height:calc(1lh + .52rem)}
.seg.theme svg{width:14px; height:14px; display:block; fill:none; stroke:currentColor;
               stroke-width:2; stroke-linecap:round; stroke-linejoin:round}
/* The row narrows before it collapses, and this is the band where that happens. It used to
   sit at 900px — below the collapse, where `nav` is `display:contents` and a gap on it does
   nothing at all. The rule was dead for as long as it has existed. */
@media (max-width:1200px){
  nav{gap:1.4rem}
  .navlinks{gap:1.4rem}
}
/* One mobile behavior for the whole family. Below this width the links do not fit beside
   the wordmark, and every page in the three sites used to answer that differently — some
   wrapped the bar, some wrapped the nav, and the two whose `.bar` had no `flex-wrap` at
   all let the wordmark itself break in half. They collapse behind a button instead.

   1000px, measured on blust.ch rather than chosen. This said 640 until 2026-09-16, and
   between 641 and 1035 the bar wrapped in English and to 1099 in German: the brand on one
   row and the nav orphaned under it, no rule, no alignment. It was not a German problem and
   it did not arrive with a sixth nav item — five items already wrapped from 641 to 850 in
   English. It went unseen because the checks that watch this row read page-level sideways
   scroll and the wordmark's height, and a wrapped bar causes neither.

   The number is the longest language's, not the shortest: German needs 1000 with the row
   narrowed, English 920. One number for the family, set by whichever language needs most,
   because a header that collapses at a different width per language is a header a visitor
   cannot predict. Every width this newly collapses was already broken, so nothing that
   worked has been taken away.

   The language control stays on the bar. It is two characters, it is used constantly by a
   bilingual audience, and a language a visitor cannot find is worse than one menu tap
   saved. It keeps the right-hand end of the row, with the theme control beside it; the menu
   button holds the left-hand corner, which is where a thumb goes looking for it. */
/* The row collapses when it does not fit, and `data-nav` is how the page says so. It used to
   be a width — 640 until 2026-09-16, then 1000 — and a width cannot be right for three sites
   whose navs hold three, four and six items. Measured, German needed 720 on guestgraph.io,
   900 on companygraph.io and 1000 on blust.ch, so any single number gave two of them a menu
   button where a row would have read perfectly well.

   The number is gone. The nav-fit block measures what the row needs against what it has and
   sets the attribute, so this is right for every site, every language, and the next nav item
   nobody has added yet. See blocks/nav-fit.js for how it measures without a flash.

   Without JavaScript the attribute is never set and the row stays wide, wrapping on a narrow
   screen. That is not a regression: with JavaScript off the button here has never opened
   anything, so a visitor went from six unreachable links to six wrapped but reachable ones. */
/* The menu button takes the left-hand corner. It cannot be moved in the DOM — the bar's
   markup is written per page, sixteen of them across three repositories, while this fence
   is CSS alone — so `nav` stops generating a box and its children become items of `.bar`
   itself. The button then reaches the corner with `order`, in flow, aligned by the same
   `align-items:center` as everything else in the row.

   Absolute positioning was the first attempt and it fought the bar's own wrapping: `.bar`
   has `flex-wrap` and already went to two rows at 360px before this button moved, so a
   vertically centered button hung in the gap between them. Padding the wordmark clear of it
   then inflated `.brand` enough that `mobileNav` reported a broken wordmark — correctly,
   since that check reads the brand's height to find a wrapped one. `.bar` takes the
   positioning `nav` gives up, so the panel still has something to hang from. */
:root[data-nav="compact"] .bar{position:relative; gap:12px}
:root[data-nav="compact"] nav{display:contents}
:root[data-nav="compact"] .burger{display:inline-flex; order:-1}
:root[data-nav="compact"] .brand{margin-right:auto}
/* The panel spans the bar rather than hugging its longest word, so the row of controls
   above it and the panel below share one pair of edges. Its geometry is three custom
   properties because the theme control has to land in its top-right corner while living
   outside it in the DOM — see below — and a corner described twice is a corner that
   drifts the first time either number is touched. */
:root[data-nav="compact"] .bar{--drawer-gap:.85rem; --drawer-pad-y:.55rem; --drawer-pad-x:1.1rem;
     /* Half the difference between a link's box and the theme control's, so the control
        and the first link read as one row instead of two things that nearly line up.
        Measured, not derived — a link's height comes from its own padding and line box,
        which CSS cannot subtract here. Changing `.navlinks a`'s padding or the control's
        height moves it; the centers are 117 and 118 as it stands. */
     --drawer-first-row:.5rem}
:root[data-nav="compact"] .navlinks{display:none; position:absolute; top:calc(100% + var(--drawer-gap));
          left:0; right:0; z-index:30;
          flex-direction:column; align-items:flex-start; gap:0;
          padding:var(--drawer-pad-y) var(--drawer-pad-x);
          background:var(--raise); border:1px solid var(--rule); border-radius:10px}
:root[data-nav="compact"] .navlinks[data-open="true"]{display:flex}
/* The theme control leaves the bar. Measured at 393px: the bar has 338px to spend and the
   brand's 136 plus the button's 40 plus the switchers' 147 need 347 even at a 12px gap, so
   the row wrapped on every phone width tested — 320 through 412 — and the header stood
   101px tall before a word of content. The wordmark is the other lever and the contract
   closes it: it is nowrap by rule, and `mobileNav` reads its height to catch one that
   broke. Dropping the theme control is what is left, and it buys one row of 40px
   everywhere down to 320.

   It is not lost. Opening the menu drops it below the language control it belongs with —
   positioned, not in flow, so the bar stays 40px and nothing above it moves. In flow it
   pushed the language control onto a second row as the menu opened, which is a control
   jumping out from under a thumb that was reaching for it.

   `.bar .theme` and not `.theme`: the control is a `.seg` too, and `.seg{display:inline-flex}`
   is the same specificity and sits later in the cascade, so the bare class lost and the
   control stayed on the bar with the file looking correct. */
:root[data-nav="compact"] .bar .theme{display:none}
/* Positioned into the panel's top-right corner, not placed in it: `.switchers` is a
   sibling of `.navlinks`, and the bar's markup is written per page — sixteen of them
   across three repositories — while this fence is CSS alone. Anchoring it to the same
   three properties the panel uses is what makes the two agree.
   Above the panel's own z-index, or the panel paints over it. A tap on it does not close
   the menu: the page's handler closes on a click outside `nav`, and `.switchers` is
   inside `nav`. */
:root[data-nav="compact"] .navlinks[data-open="true"] ~ .switchers .theme{
  display:inline-flex; position:absolute; z-index:31;
  top:calc(100% + var(--drawer-gap) + var(--drawer-pad-y) + var(--drawer-first-row));
  right:var(--drawer-pad-x)}
/* Tall enough to be a comfortable target; the underline still hugs the word, because
   each item is only as wide as its own text. */
:root[data-nav="compact"] .navlinks a{padding:.8rem 0}

.title h1{font-family:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
          letter-spacing:-.035em; line-height:1.0;
          font-size:clamp(2.2rem,6vw,4.6rem)}
.title h1 .r70{display:block; font-weight:300; color:var(--dim)}
.title h1 .rcl{display:block; font-weight:800}
.title h1 em{font-style:normal; color:var(--c-firm)}
.tagline{margin-top:1.6rem; font-size:clamp(1.1rem,1.9vw,1.4rem); color:var(--dim);
         max-width:46ch; line-height:1.4}
@media (max-width:900px){ .tagline{max-width:100%} }

footer{padding:0 0 2rem; display:flex; flex-wrap:wrap; gap:.9rem 2.6rem; align-items:center;
       font-family:"Plex Mono",monospace; font-size:.76rem; letter-spacing:.08em; color:var(--dim)}
footer a{color:var(--c-mid); text-decoration:none}
footer a:hover, footer a:focus-visible{text-decoration:underline}
footer .credit{display:inline-flex; align-items:center; gap:.5em; vertical-align:-.25em;
               font-family:"Instrument Sans", ui-sans-serif, system-ui, sans-serif;
               font-size:.84rem; letter-spacing:0; color:var(--ink)}
footer .credit .rbmark{display:flex}
footer .credit .rbmark svg{width:14px; height:14px; display:block}
footer .credit .plate{fill:var(--raise); stroke:var(--rule); stroke-width:1.5}
footer .credit .rb{fill:var(--c-mid)}
footer .credit b{font-weight:600}
footer .credit b em{font-style:normal; color:var(--c-mid)}
footer .credit:hover, footer .credit:focus-visible{text-decoration:none}
footer .credit:hover b em, footer .credit:focus-visible b em{color:var(--ink)}
footer a[aria-current="page"]{color:var(--c-firm)}

.value{border-top:2px solid var(--rule); padding-top:1.1rem; margin-top:1.9rem}
.value h3{font-family:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
          font-weight:700; letter-spacing:-.02em; font-size:clamp(1.15rem,2.1vw,1.5rem)}
.value .tagline{margin-top:.5rem; color:var(--c-firm); max-width:62ch}
.value p{margin-top:.9rem; color:var(--dim); max-width:70ch; line-height:1.6}

/* The board. --cols (the seat column) and --phase (the width of each phase column) are
   declared once and used by the head row and every summary, which is what lines the columns
   up across rows without a table. Only the seat column is a template track: each cell after
   it opens a column of its own at --phase, so the board has as many phase columns as the
   process has phases and never an empty one or a wrapped one. */
/* blocks/surfaces.css declares this same base rule for its own .mk. */
.mk{width:1.05em; height:1.05em; flex:none; vertical-align:-.16em}
.mk.human{color:var(--c-firm)}
.mk.agent{color:var(--c-mid)}
.hw .mk{width:2.3rem; height:2.3rem}

.hdrail{display:flex; gap:2rem; align-items:center; justify-content:space-between;
        padding-bottom:1.1rem; border-bottom:1px solid var(--rule); margin-top:.9rem}
.whos{display:flex; gap:2.6rem}
.hw{display:flex; gap:.7rem; align-items:center}
.hw .nm{font-family:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
        font-weight:700; font-size:1.05rem}
.openall{background:none; border:1px solid var(--rule); border-radius:5px; color:var(--dim);
         font:inherit; font-size:.76rem; padding:.28rem .7rem; cursor:pointer}
.openall:hover, .openall:focus-visible{color:var(--c-mid); border-color:var(--c-mid)}

/* Three cell marks, one hue. tokens.css allows one hue at four brightnesses and refuses a
   second, so what a color would have carried is carried by shape. */
.g{display:inline-block; width:10px; height:10px; margin:0 1px}
.g.ex{background:var(--c-mid); border-radius:50%}
.g.su{border:1.4px solid var(--c-weak); border-radius:50%}
.g.ga{width:0; height:0; border-left:6px solid transparent; border-right:6px solid transparent;
      border-bottom:10px solid var(--c-firm); vertical-align:-1px}
.legend{display:flex; gap:1.5rem; flex-wrap:wrap; margin-top:1.1rem; color:var(--dim);
        font-size:.76rem}
.legend span{display:flex; align-items:center; gap:.45rem}

.grid{--cols:30%; --phase:1fr; margin-top:0}
.ghead{display:grid; grid-template-columns:var(--cols); grid-auto-flow:column;
       grid-auto-columns:var(--phase); border-bottom:1px solid var(--rule);
       padding:.9rem 0 .8rem}
.ghead > span{text-align:center}
.ghead > span:first-child{text-align:left}
.phnum{color:var(--c-weak); font-size:.66rem; letter-spacing:.12em; display:block;
       font-family:"Plex Mono", ui-monospace, Menlo, monospace}
.phname{font-family:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
        font-weight:700; font-size:.9rem; color:var(--ink)}
.grid details{border-bottom:1px solid var(--rule)}
.grid summary{display:grid; grid-template-columns:var(--cols); grid-auto-flow:column;
              grid-auto-columns:var(--phase); align-items:center;
              list-style:none; cursor:pointer; padding:.62rem 0}
.grid summary::-webkit-details-marker{display:none}
.grid summary:hover{background:var(--press)}
.grid summary:focus-visible{outline:2px solid var(--c-mid); outline-offset:-2px}
.grid summary > span{text-align:center}
.grid .sname{display:flex; align-items:center; gap:.6rem; text-align:left}
.grid .sname .tw{font-weight:600; font-size:.9rem}
/* The disclosure triangle is this page's only affordance that a row opens, since the page
   carries no tooltip: the card is the seat's detail, and a hover showing a shorter version
   of what a click shows in full is a second answer to one question. */
.grid .sname::before{content:""; width:0; height:0; border-style:solid; border-width:4px 0 4px 6px;
                     border-color:transparent transparent transparent var(--c-weak);
                     transition:transform .12s ease; flex:none}
.grid details[open] .sname::before{transform:rotate(90deg); border-left-color:var(--c-mid)}
.grid details[open] .sname .tw{color:var(--c-firm)}
.grid details.human summary{background:var(--press)}
/* Full width, not an indent: the References table under a role wrapped its URLs at anything
   narrower. The card's own prose keeps a measure inside it. */
.grid .drawer{padding:.3rem 0 1.5rem}
.grid .drawer .card{width:100%}
@media (prefers-reduced-motion: reduce){ .grid .sname::before{transition:none} }
/* The phases in words, under the board that only names them. A grid rather than a
   table: two columns, the phase and its one line, and the phase column sized to the longest
   name so the sentences start on one edge. */
.phases{margin-top:1.9rem; padding-top:1.5rem; border-top:1px solid var(--rule);
        display:grid; grid-template-columns:max-content 1fr; gap:.55rem 1.4rem}
.phases dt{display:flex; align-items:baseline; gap:.5rem; white-space:nowrap}
.phases dd{margin:0; color:var(--dim); font-size:.93rem; line-height:1.5; max-width:72ch}
@media (max-width:640px){
  .phases{grid-template-columns:1fr; gap:.2rem 0}
  .phases dd{margin-bottom:.9rem}
}
@media (max-width:900px){
  /* The board stays a board. Its argument is a column — which seats carry a phase's gate,
     say, is read off the shape of the column rather than off any one row — so a form with
     no columns has no argument left to make. The phase names give way to their numbers
     and the columns narrow; the block under the board is what says which number is which
     phase, and it earns its place twice over here. */
  .grid{--cols:minmax(0,1fr); --phase:2.1rem}
  .ghead .phname{display:none}
  .ghead .phnum{font-size:.74rem; color:var(--dim); letter-spacing:.08em}
  .grid summary{padding:.72rem 0}
  .grid .sname .tw{font-size:.86rem}
  .g{width:9px; height:9px; margin:0}
  .g.ga{border-left-width:5px; border-right-width:5px; border-bottom-width:9px}
  .hdrail{flex-wrap:wrap; gap:1rem}
  .whos{gap:1.4rem}
}
@media (max-width:640px){
  /* Side by side, the head rail's profiles wrap their "holds … of …" line onto a second line
     and put the last one hard against the edge. One under the other, each reads on one line. */
  .whos{flex-direction:column; gap:.9rem}
  .hdrail{align-items:flex-start}
  .grid{--cols:minmax(0,1fr); --phase:1.8rem}
  .grid .sname{gap:.42rem}
  .grid .sname .tw{font-size:.8rem}
}
/* One board per process when a model holds more than one: the process's name and tagline
   head its board, one step below the section's h2 and in the title block's own terms: the
   name in the display face at the weight the phase names use, the tagline in --dim as the
   title block's is. `section.proc` is a <section>, so the page's own `section` rule would
   put a section's full gap between the label and the first board; the first sits where
   the head rail would, and each one after takes the figure section's gap. */
.proc{margin-top:.9rem}
.proc + .proc{margin-top:clamp(2rem,5vh,3.5rem)}
.procname{font-family:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
          font-weight:700; letter-spacing:-.02em; font-size:clamp(1.15rem,2.1vw,1.5rem);
          color:var(--ink)}
.proctag{margin-top:.4rem; color:var(--dim); max-width:62ch}

/* blocks/team.css declares this same base rule for its own .mk. */
.mk{width:1.05em; height:1.05em; flex:none; vertical-align:-.16em}
.mk.hand{color:var(--c-firm)}
.mk.build{color:var(--c-mid)}

/* The lineage. Three columns on a wide screen — the model, the makers, the surfaces — laid out
   by nesting, so the markup is the tree the drawing shows and a reader with no CSS gets the
   same order. The wires sit behind it and are drawn by the page from where the nodes landed. */
.lineage{position:relative; display:grid; grid-template-columns:minmax(0,13rem) minmax(0,1fr);
         column-gap:clamp(3rem,7vw,6rem); align-items:center; margin-top:1.4rem}
.wires{position:absolute; inset:0; width:100%; height:100%; overflow:visible; pointer-events:none}
.wires path{fill:none; stroke:var(--rule); stroke-width:1.5; transition:stroke .2s ease}
.wires path.hand{stroke-dasharray:5 5}
/* --c-path is the token for exactly this: the way back to the root from what is focused. */
.wires path.on{stroke:var(--c-path); stroke-width:2}
.ln-model{position:relative; padding:1.1rem 1.2rem; border:1.5px solid var(--c-firm); border-radius:10px;
          background:var(--raise)}
.ln-model .nm{font-family:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif; font-weight:800;
              font-size:clamp(1.2rem,2vw,1.5rem); letter-spacing:-.02em; line-height:1.05; margin-top:.35rem}
.ln-model .at{font-size:.78rem; color:var(--c-mid); margin-top:.3rem}
.ln-groups, .ln-surfaces{list-style:none}
.ln-groups{display:grid; gap:2.2rem}
.ln-group{display:grid; grid-template-columns:minmax(0,12rem) minmax(0,1fr);
          column-gap:clamp(2.5rem,6vw,5rem); align-items:center}
.ln-maker{position:relative; display:flex; gap:.6rem; align-items:center; padding:.5rem 0}
.ln-maker .mk{width:1.5rem; height:1.5rem}
.ln-maker .who{font-weight:600; font-size:.92rem; line-height:1.25}
.ln-maker .how{display:block; font-size:.76rem; color:var(--dim); font-weight:400}
.ln-surfaces{display:grid; grid-template-columns:minmax(0,1fr); gap:.6rem}
.ln-surfaces li{min-width:0}
.ln-s{position:relative; width:100%; text-align:left; font:inherit; color:var(--ink); cursor:pointer;
      display:flex; flex-direction:column; gap:.1rem; padding:.7rem .95rem;
      background:var(--ground); border:1px solid var(--rule); border-radius:8px;
      transition:border-color .15s ease, background-color .15s ease}
.ln-s:hover{border-color:var(--c-mid)}
.ln-s:focus-visible{outline:2px solid var(--c-mid); outline-offset:2px}
.ln-s .nm{font-family:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif; font-weight:700; font-size:1.02rem}
/* An address, so mono: it is a record value, not prose. */
.ln-s .host{font-family:"Plex Mono", ui-monospace, Menlo, monospace; font-size:.72rem; color:var(--dim);
            overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ln-s[aria-pressed="true"]{border-color:var(--c-path); background:var(--press)}
.ln-s[aria-pressed="true"] .nm{color:var(--c-firm)}
@media (prefers-reduced-motion: reduce){ .wires path, .ln-s{transition:none} }
/* No room for three columns: the drawing becomes the tree it already is, its lines drawn as
   rules — dashed under the hand, as the wire is. */
@media (max-width:760px){
  .wires{display:none}
  .lineage{grid-template-columns:minmax(0,1fr); row-gap:0}
  .ln-model{justify-self:start}
  .ln-groups{gap:0; margin-left:1rem; padding:1.2rem 0 0 1.1rem; border-left:1.5px solid var(--rule)}
  .ln-group{grid-template-columns:minmax(0,1fr); padding-bottom:1.2rem}
  .ln-surfaces{margin-left:.7rem; padding-left:1rem; border-left:1.5px solid var(--rule)}
  .ln-group.hand .ln-surfaces{border-left-style:dashed}
}
