/* The viewport chrome, shared by the Region Atlas and the receptor page
   so a brain view looks the same wherever it appears. Both pages define
   the ink/paper custom properties this leans on. */

.view{ border:1px solid var(--hair); display:flex; flex-direction:column; min-width:0; }
.view-cap{
  display:flex; flex-wrap:wrap; justify-content:space-between; align-items:baseline;
  gap:.35rem .8rem; padding:.6rem .8rem .5rem; border-bottom:1px solid var(--hair);
}
.view-cap b{
  font-family:var(--font-brand); font-weight:500; font-size:.68rem;
  letter-spacing:.28em; text-transform:uppercase;
}
.view-cap span{
  font-family:var(--font-serif); font-style:italic; font-size:.82rem; color:var(--ink-60);
}

/* per-viewport controls, sat on their own rule beneath the caption */
.view-tools{
  display:flex; flex-wrap:wrap; align-items:center; gap:.36rem .6rem;
  padding:.4rem .8rem; border-bottom:1px solid var(--hair);
}
.tool-label{
  font-family:var(--font-brand); font-weight:500; font-size:.55rem;
  letter-spacing:.22em; text-transform:uppercase; color:var(--ink-60);
}
.centre-btn{
  margin-left:auto; height:1.8rem; padding:0 .6rem;
  display:inline-flex; align-items:center;
}

/* segmented switch — one joined run of square cells, the active one inked */
.seg{ display:inline-flex; border:1px solid var(--hair); align-self:center; }
.seg-btn{
  border:0; border-left:1px solid var(--hair); border-radius:0;
  background:var(--paper); color:var(--ink);
  font-family:var(--font-brand); font-weight:500;
  text-transform:uppercase; cursor:pointer; line-height:1;
  width:1.8rem; height:1.8rem; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
}
.seg-btn:first-child{ border-left:0; }
@media (hover: hover){ .seg-btn:hover{ background:var(--ink); color:var(--paper); } }
.seg-btn.active{ background:var(--ink); color:var(--paper); }
.seg-word{ font-size:.46rem; letter-spacing:.06em; }
.seg-arrow{ font-size:.74rem; letter-spacing:-.04em; }

.mri-stage{ position:relative; background:#000000; height:clamp(240px,36vh,430px); height:clamp(240px,36dvh,430px); }
.mri-stage canvas{ position:absolute; inset:0; width:100%; height:100%; display:block; outline:none; }

/* ── page layout: a rail of inputs beside the viewports, shared by every
   page so the three read as one instrument ── */
.rail{ display:flex; flex-direction:column; gap:var(--gap); }
.card{ border:1px solid var(--hair); padding:1rem 1.05rem 1.1rem; background:var(--paper); }
.card h2{
  font-family:var(--font-brand); font-weight:500; font-size:.68rem;
  letter-spacing:.3em; text-transform:uppercase; text-align:center;
  border-bottom:1px solid var(--hair); padding-bottom:.55rem; margin-bottom:.75rem;
}
.views{ display:grid; grid-template-columns:1fr 1fr; gap:var(--gap); min-width:0; }
.studio{ display:grid; grid-template-columns:300px minmax(0,1fr); gap:var(--gap); align-items:start; }
.sec-h{
  font-family:var(--font-brand); font-weight:600; font-size:.66rem;
  letter-spacing:.3em; text-transform:uppercase; color:var(--ink);
  border-bottom:1px solid var(--ink); padding:.2rem .1rem .45rem; margin:0 0 var(--gap);
  display:flex; align-items:baseline; justify-content:space-between; gap:.6rem;
}
.selwrap{ position:relative; width:100%; }
.selwrap::after{
  content:""; position:absolute; right:.75rem; top:50%; transform:translateY(-35%);
  border-left:4px solid transparent; border-right:4px solid transparent;
  border-top:5px solid var(--ink); pointer-events:none;
}
select{
  width:100%; appearance:none; -webkit-appearance:none; border-radius:0;
  border:1px solid var(--hair); background:var(--paper); color:var(--ink);
  font-family:var(--font-brand); font-size:.92rem; padding:.55rem 1.8rem .5rem .6rem;
  cursor:pointer;
}

/* the view-switch button, used in title strips, rails and viewport rules */
.ts-btn{
  border:1px solid var(--hair); background:var(--paper); color:var(--ink);
  font-family:var(--font-brand); font-weight:500; font-size:.62rem;
  letter-spacing:.2em; text-transform:uppercase; cursor:pointer;
  padding:.5rem .7rem .42rem; text-decoration:none; line-height:1;
}
.ts-btn.active{ background:var(--ink); color:var(--paper); }
@media (hover: hover){ .ts-btn:hover{ background:var(--ink); color:var(--paper); } }

/* ── narrow screens ──────────────────────────────────────────────────────
   A 300px rail beside the viewports needs a wide window. Below that the
   studio becomes one column with the viewports still on top, and the rail
   reads as a row of cards beneath them. */
@media (max-width:1100px) and (orientation:portrait),
       (max-width:900px) and (orientation:landscape){
  .studio{ grid-template-columns:1fr; }
  .centre{ order:-1; }
  .title-strip .ts-views{ margin-left:0; width:100%; }
  .rail{ display:grid; grid-template-columns:1fr 1fr; align-items:start; }
  .rail .sec-h{ grid-column:1 / -1; }
}
@media (max-width:760px){
  .rail{ grid-template-columns:1fr; }
  /* On a phone each viewport is most of a screen, so leading with them would
     bury the controls. Here the rail comes first and the brain follows. */
  .centre{ order:0; }
  /* keep the boxes two-up: stacking all four puts the controls a screen and
     a half below the fold. The chrome sheds its wordier parts to fit. */
  .views{ grid-template-columns:1fr 1fr; }
  .mri-stage{ height:clamp(150px,38vw,240px); }
  .view-cap{ padding:.45rem .55rem .35rem; }
  .view-cap span{ display:none; }
  .view-tools{ padding:.3rem .5rem; gap:.3rem; }
  .view-tools .tool-label{ display:none; }
  .centre-btn{ margin-left:auto; height:1.6rem; padding:0 .45rem; font-size:.5rem; }
  .seg-btn{ width:1.6rem; height:1.6rem; }
}
@media (max-width:430px){
  .views{ grid-template-columns:1fr; }
  .mri-stage{ height:clamp(190px,54vw,280px); }
}

/* ── narrow screens: the tabs stack, one to a line ──────────────────────
   Six tabs wrapped into ragged rows on a phone, breaking mid-row and leaving
   the current tab hard to find. Stacked, each one reads as its own line.
   Every page declares .nav-row in its own sheet, so the class is doubled
   here to outrank those rules whichever order the sheets land in. */
@media (max-width:760px){
  .nav-row.nav-row{ flex-direction:column; gap:.62rem; }
  .nav-row.nav-row a{ display:block; }
}

/* ── the tab strip can never be wider than the page ─────────────────────
   Two guarantees, whatever the browser, the zoom level or the fonts that
   actually loaded. First, the strip wraps its own tabs and, when the
   compact masthead below makes it a flex item, it may shrink to the line
   rather than keep its full natural width and spill past both edges —
   the centred strip was seen clipped at both ends in exactly that case.
   Second, between a phone and a wide desktop the tabs are set a little
   tighter, so eight of them and the two buttons sit on one row from
   about 1180px up and on two tidy rows below, instead of three ragged
   ones. Classes are doubled to outrank the per-page declarations. */
.nav-row.nav-row{ flex-wrap:wrap; min-width:0; max-width:100%; box-sizing:border-box; }
.masthead.masthead > .nav-row{ flex:0 1 auto; }
/* the type, its tracking and the gaps all scale with the viewport, from a
   compact setting at 761px up to the full one at about 1700px, so the strip
   grows with the window rather than jumping between sizes at a breakpoint */
@media (min-width:761px){
  .nav-row.nav-row{ gap:.3rem clamp(.8rem, .2rem + 1.2vw, 2rem); }
  .nav-row.nav-row a{
    font-size:clamp(.64rem, .55rem + .11vw, .74rem);
    letter-spacing:clamp(.2em, .1em + .12vw, .3em);
  }
}
/* the Log in button and the theme toggle are one unit: where the eight
   tabs fill a row and the buttons do not fit beside them, both drop to
   the next row together, rather than one of them falling alone. The
   group inherits the strip's gap so the spacing reads as one row. */
.nav-row .nav-tools{ display:inline-flex; align-items:center; gap:inherit; }
}

/* ── enlarge: one box taking the whole grid ── */
.views.solo{ grid-template-columns:1fr; }
.views.solo .view{ display:none; }
.views.solo .view.solo-on{ display:flex; }
.views.solo .mri-stage{ height:clamp(420px,68vh,900px); height:clamp(420px,68dvh,900px); }
.zoom-btn{ padding:0 .5rem; height:1.8rem; display:inline-flex; align-items:center; }

/* the 3D box leads the grid; the atlas names it "render", the other two "Ren" */
.views .view[data-box="Ren"], .views .view[data-box="render"]{ order:-1; }

/* ── slice tool: a cut on each axis, run from the edges ─────────────────
   Each control sits on the edge it works along — up–down down one side,
   front–back down the other, left–right along the bottom — so the middle of
   the box stays clear and the brain is never behind a slider. Each name
   reads in the direction its own cut travels. */
.slice-panel{
  position:absolute; inset:0; z-index:2;
  display:none; pointer-events:none;
}
.slice-panel.on{ display:block; }

.slice-edge{
  position:absolute; pointer-events:auto;
  display:flex; align-items:center; gap:.35rem;
}
.slice-edge .ax{
  font-family:var(--font-brand); font-weight:500; font-size:.48rem;
  letter-spacing:.2em; text-transform:uppercase; white-space:nowrap;
  color:#9A9A9A; transition:color .2s ease;
  text-shadow:0 0 4px #000, 0 0 4px #000;
}
.slice-edge.cutting .ax{ color:#FFFFFF; }

/* the two vertical edges */
.slice-edge.left, .slice-edge.right{
  top:10px; bottom:10px; width:30px;
  flex-direction:column; justify-content:center;
}
.slice-edge.left{ left:3px; }
.slice-edge.right{ right:3px; }
.slice-edge.left .ax{ writing-mode:vertical-rl; transform:rotate(180deg); }
.slice-edge.right .ax{ writing-mode:vertical-rl; }

/* the bottom edge, held clear of both verticals */
.slice-edge.bottom{ left:36px; right:36px; bottom:5px; height:20px; }

.slice-range{
  -webkit-appearance:none; appearance:none;
  background:transparent; cursor:pointer; margin:0;
}
.slice-edge.bottom .slice-range{ flex:1; min-width:0; height:18px; }
.slice-edge.left .slice-range, .slice-edge.right .slice-range{
  writing-mode:vertical-lr; direction:rtl;
  width:18px; flex:1; min-height:0;
}
.slice-range::-webkit-slider-runnable-track{
  background:rgba(255,255,255,.28); border-radius:2px;
}
.slice-edge.bottom .slice-range::-webkit-slider-runnable-track{ height:2px; }
.slice-edge.left .slice-range::-webkit-slider-runnable-track,
.slice-edge.right .slice-range::-webkit-slider-runnable-track{ width:2px; }
.slice-range::-moz-range-track{ background:rgba(255,255,255,.28); border-radius:2px; }
.slice-range::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none;
  width:12px; height:12px; border-radius:50%;
  background:#FFFFFF; border:1px solid #000000; margin-top:-5px;
}
.slice-edge.left .slice-range::-webkit-slider-thumb,
.slice-edge.right .slice-range::-webkit-slider-thumb{ margin:0 0 0 -5px; }
.slice-range::-moz-range-thumb{
  width:12px; height:12px; border-radius:50%;
  background:#FFFFFF; border:1px solid #000000;
}
.slice-range:focus-visible{ outline:1px solid #FFFFFF; outline-offset:3px; }

.slice-btn.active{ background:var(--ink); color:var(--paper); }

@media (max-width:760px){
  .slice-edge.left, .slice-edge.right{ width:24px; top:6px; bottom:6px; }
  .slice-edge.bottom{ left:28px; right:28px; bottom:3px; }
  .slice-edge .ax{ font-size:.42rem; letter-spacing:.14em; }
}

/* ── inside a native shell ──────────────────────────────────────────────
   native.js stamps the platform on the document, so these apply only in the
   App Store and Play Store builds and never to the website.

   A phone has furniture the browser used to keep clear of: a notch, a home
   indicator, a status bar the webview draws underneath. The page is inset by
   whatever the device says it needs, which is zero on a device that needs
   nothing. Rubber-band scrolling is turned off because dragging a brain
   around should not also drag the page, and long-press selection is turned
   off on the chrome for the same reason — but not on the prose, which is
   there to be read and quoted. */
body{
  padding-top:max(env(safe-area-inset-top, 0px), var(--safe-area-inset-top, 0px));
  padding-bottom:max(env(safe-area-inset-bottom, 0px), var(--safe-area-inset-bottom, 0px));
  padding-left:max(env(safe-area-inset-left, 0px), var(--safe-area-inset-left, 0px));
  padding-right:max(env(safe-area-inset-right, 0px), var(--safe-area-inset-right, 0px));
}
:root[data-native] body{
  overscroll-behavior:none;
}
:root[data-native]{ -webkit-tap-highlight-color:transparent; }
:root[data-native] .masthead,
:root[data-native] .nav-row,
:root[data-native] .rail,
:root[data-native] .title-strip,
:root[data-native] .view-cap,
:root[data-native] .view-tools{
  -webkit-user-select:none; user-select:none;
}
/* a canvas is dragged, never selected, and never offers a callout */
:root[data-native] canvas{
  -webkit-user-select:none; user-select:none;
  -webkit-touch-callout:none;
}

/* ── the app's top bar ───────────────────────────────────────────────────
   Inside the native app the masthead and its tab row give way to a bar
   pinned to the top, built by assets/navbar.js: back on the left, the
   title in the middle, theme and account on the right. The website never
   sees any of this. */
:root[data-native] .masthead{ display:none; }
/* the inset comes from the browser where it reports one and from Capacitor's
   SystemBars plugin on Android, which writes the real value into these
   variables since Android 15 draws the app under the bars either way */
:root[data-native]{ --vn-top-inset:max(env(safe-area-inset-top, 0px), var(--safe-area-inset-top, 0px)); }
:root[data-native] body{ padding-top:calc(var(--vn-top-inset) + 44px); }
.vn-bar{
  position:fixed; top:0; left:0; right:0; z-index:60;
  box-sizing:border-box; height:calc(var(--vn-top-inset, env(safe-area-inset-top)) + 44px);
  padding:var(--vn-top-inset, env(safe-area-inset-top)) 6px 0 6px;
  display:grid; grid-template-columns:minmax(max-content,1fr) minmax(0,max-content) minmax(max-content,1fr); align-items:center;
  background:color-mix(in srgb, var(--paper) 84%, transparent);
  -webkit-backdrop-filter:saturate(180%) blur(20px); backdrop-filter:saturate(180%) blur(20px);
  border-bottom:1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  color:var(--ink); font-family:var(--font-brand);
  -webkit-user-select:none; user-select:none;
  view-transition-name:vn-bar;
}
/* The two ends are never narrower than what they hold, the title has what
   is left and is cut with an ellipsis rather than covered: on a phone the
   menu, account and theme buttons once sat over the brand, with Log out on
   two lines. Where the bar is wide enough the ends share the spare room
   equally, which keeps the title in the centre of the bar on an iPad. */
.vn-bar-left{ display:flex; align-items:center; justify-self:start; }
.vn-bar-right{ display:flex; align-items:center; justify-self:end; gap:.4rem; }
.vn-bar-title{
  min-width:0; font-size:1.02rem; font-weight:600; letter-spacing:.01em; text-align:center;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; padding:0 .4rem;
}
.vn-bar-brand{ font-weight:500; font-size:1.08rem; }
.vn-back{
  display:inline-flex; align-items:center; gap:.1rem; max-width:100%;
  background:none; border:0; padding:0 .5rem 0 .1rem; min-height:44px;
  color:var(--ink); font:inherit; font-size:1.02rem; cursor:pointer; -webkit-tap-highlight-color:transparent;
}
.vn-back:active{ opacity:.45; }
.vn-chevron{
  flex:none; width:.62rem; height:.62rem; margin:0 .32rem 0 .3rem;
  border-left:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(45deg) translate(1px,-1px);
}
.vn-back-label{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:7em; }
/* when the title would still be cut, the back button keeps its chevron and
   drops its label, as an iPhone's bar does (navbar.js measures) */
.vn-bar.vn-bar-tight .vn-back-label{ display:none; }
.vn-bar.vn-bar-tight .vn-back{ padding-right:.2rem; }
.vn-bar .theme-toggle{ padding:.22rem .5rem; }
.vn-bar .vn-auth-slot{ display:inline-flex; align-items:center; gap:.4rem; }
.vn-bar .vn-auth-btn, .vn-bar .vn-auth-name{ white-space:nowrap; }
.vn-bar .vn-auth-name{ max-width:9.6em; letter-spacing:.1em; }
/* signed in, the bar shows the account button alone: it opens the account
   card, and Log out lives there, so the bar keeps to one line on a phone */
.vn-bar .vn-auth-name + .vn-auth-btn{ display:none; }
@media (max-width:480px){ .vn-bar .theme-toggle #themeLbl{ display:none; } }

/* pages slide like screens: in from the right going forward, out again
   coming back. Only the app opts in (navbar.js adds the @view-transition
   rule), so on the website these rules never fire. */
::view-transition-old(root), ::view-transition-new(root){
  animation-duration:.34s; animation-timing-function:cubic-bezier(.32,.72,0,1);
  mix-blend-mode:normal;
}
:root[data-vn-dir="push"]::view-transition-old(root){ animation-name:vn-out-left; }
:root[data-vn-dir="push"]::view-transition-new(root){ animation-name:vn-in-right; }
:root[data-vn-dir="back"]::view-transition-old(root){ animation-name:vn-out-right; }
:root[data-vn-dir="back"]::view-transition-new(root){ animation-name:vn-in-left; }
::view-transition-old(vn-bar), ::view-transition-new(vn-bar){ animation-duration:.2s; }
@keyframes vn-in-right{ from{ transform:translateX(100%); } }
@keyframes vn-out-left{ to{ transform:translateX(-28%); opacity:.55; } }
@keyframes vn-in-left{ from{ transform:translateX(-28%); opacity:.55; } }
@keyframes vn-out-right{ to{ transform:translateX(100%); } }
@media (prefers-reduced-motion: reduce){
  ::view-transition-old(root), ::view-transition-new(root){ animation:none; }
}

/* A touch screen has no hover and no scroll wheel, so the viewports get the
   room instead: a stage sized for a thumb, and the gesture claimed from the
   browser so a pinch zooms the brain rather than the page. */
@media (pointer:coarse){
  .mri-stage{ touch-action:none; }
}

/* ── landscape on a short screen: the chrome gives the height back ──────
   Landscape is the posture the app is designed in, and there the scarce
   axis is height — yet the centred masthead, the nav and the title strip
   spent some 200px of it before any content appeared. Under 940px of
   height in landscape the brand shares its line with the nav, the strip
   tightens, and the viewport grid is sized from the height that is
   actually there rather than from fixed clamps. Phones in landscape pass
   the min-width gate too, which is fine: the clamp floors keep the
   stages usable and the page simply scrolls.
   Classes are doubled where a page sheet declares the same single class,
   so these win whichever order the sheets land in. */
@media (orientation: landscape) and (max-height: 1120px) and (min-width: 761px){
  .masthead.masthead{
    display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
    column-gap:2.2rem; row-gap:0; padding:.5rem 0 0; text-align:left;
  }
  .masthead .brand{ font-size:1.3rem; }
  .nav-row.nav-row{ padding:.3rem 0 .4rem; gap:.25rem 1.05rem; }
  .nav-row.nav-row a{ font-size:.66rem; }
  .title-strip.title-strip{ padding:.45rem .9rem; margin-bottom:10px; }
  .title-strip .name{ font-size:1.05rem; }
  .masthead + * .title-strip{ margin-top:0; }

  .studio{ grid-template-columns:260px minmax(0,1fr); }

  /* the grid takes what the chrome gave back: two rows that fill the
     screen, one row that fills it alone */
  .views:not(.solo) .mri-stage{ height:clamp(200px, calc((100vh - 330px)/2), 560px); height:clamp(200px, calc((100dvh - 330px)/2), 560px); }
  .views.solo .mri-stage{ height:clamp(300px, calc(100vh - 260px), 900px); height:clamp(300px, calc(100dvh - 260px), 900px); }
}
/* the 768-tall iPads: the title strip wraps to two lines at this width, so
   the stages surrender the difference rather than push past the fold */
@media (orientation: landscape) and (max-height: 800px) and (min-width: 761px){
  .views:not(.solo) .mri-stage{ height:clamp(185px, calc((100vh - 372px)/2), 560px); height:clamp(185px, calc((100dvh - 372px)/2), 560px); }
}

/* ── a stage whose GL context has been taken away ────────────────────────
   iPadOS evicts background WebGL contexts; coming back then shows black.
   stage-lifecycle.js drops this button on the stage when it happens. */
.ctx-lost{
  position:absolute; inset:0; z-index:5; width:100%;
  display:flex; align-items:center; justify-content:center;
  background:rgba(0,0,0,.82); color:#FFFFFF; border:0; cursor:pointer;
  font-family:var(--font-brand); font-weight:500; font-size:.68rem;
  letter-spacing:.22em; text-transform:uppercase;
}

/* ── a screen worked by fingers ──────────────────────────────────────────
   Apple's guidance is 44 points and nothing interactive here reached it:
   segment cells were 26px, tab buttons 27, checkboxes 14. Under a coarse
   pointer the controls grow to size; a mouse sees none of this. The
   slice-tool's edge sliders are exempt — they are custom-drawn and sized
   for touch already, and a blanket range rule would break their vertical
   writing mode. */
button, .ts-btn, .seg-btn, .barow{ touch-action:manipulation; }
@media (pointer:coarse){
  .ts-btn{ min-height:44px; }
  .seg-btn{ width:44px; height:44px; }
  .theme-toggle{ min-height:44px; }
  .barow{ min-height:44px; }
  .rchip button{ min-width:36px; min-height:36px; }
  .toggle input[type="checkbox"]{ width:22px; height:22px; }
  input[type="range"]:not(.slice-range){ height:34px; }
}
/* the grown controls thicken the chrome, so the stages give it back */
@media (pointer:coarse) and (orientation:landscape) and (max-height:1120px){
  .views:not(.solo) .mri-stage{ height:clamp(185px, calc((100vh - 412px)/2), 560px); height:clamp(185px, calc((100dvh - 412px)/2), 560px); }
  /* grown to 44px, the full toolbars wrap to two rows in a 1024-wide grid;
     the wordier parts go, as they already do on a phone */
  .view-tools .tool-label{ display:none; }
  .view-cap span{ display:none; }
}
/* the smallest landscape iPads with touch: the strip wraps twice at 44px,
   so the four-up runs small — solo view is the working mode at this size,
   and it gets the full height */
@media (pointer:coarse) and (orientation:landscape) and (max-height:800px){
  .views:not(.solo) .mri-stage{ height:clamp(155px, calc((100vh - 444px)/2), 560px); height:clamp(155px, calc((100dvh - 444px)/2), 560px); }
}

/* a zoomed diagram (diagram-gestures.js) can be dragged around by mouse,
   and the cursor should say so */
.diag-zoomed{ cursor:grab; }

/* the gesture hints speak the dialect of the pointer actually present:
   fingers hear about pinching, a mouse hears about its wheel */
.tl-touch{ display:none; }
@media (pointer:coarse){
  .tl-touch{ display:inline; }
  .tl-mouse{ display:none; }
}

/* ── 3D export and saved models, the controls a rail card holds ──────── */
.x3d .btn, .models .btn{
  display:inline-block; font-family:var(--font-brand); font-weight:500;
  font-size:.66rem; letter-spacing:.18em; text-transform:uppercase;
  border:1px solid var(--ink); background:var(--paper); color:var(--ink);
  padding:.55rem .9rem .48rem; cursor:pointer; border-radius:0;
}
.x3d .btn:disabled{ opacity:.5; cursor:default; }
@media (hover: hover){ .x3d .btn:not(:disabled):hover, .models .btn:hover{ background:var(--ink); color:var(--paper); } }
.x3d .btns{ display:flex; gap:.6rem; }
.x3d .btns .btn{ flex:1; text-align:center; }
.x3d .toggle{ display:flex; align-items:center; gap:.45rem; font-family:var(--font-serif); font-size:.92rem; cursor:pointer; }
.x3d .toggle input{ width:14px; height:14px; accent-color:var(--ink); margin:0; }
.x3d{ display:flex; flex-direction:column; gap:.55rem; margin-top:.4rem; }
.x3d .btns{ margin-top:0; }
.x3d .toggles{ display:grid; gap:.35rem; }
.x3d-note, .x3d-status, .models-note{
  font-family:var(--font-serif); font-style:italic; font-size:.86rem; line-height:1.45;
  color:var(--ink-60); margin:0;
}
.x3d-status:empty, .models-note:empty{ display:none; }
.x3d-status.err, .models-note.err{ color:var(--ink); font-style:normal; }
.models{ display:flex; flex-direction:column; gap:.55rem; margin-top:.4rem; }
.models .mform{ display:flex; gap:.5rem; align-items:stretch; }
.models .mform input{
  flex:1; min-width:0; font-family:var(--font-serif); font-size:.95rem;
  border:1px solid var(--ink); background:var(--paper); color:var(--ink);
  padding:.45rem .6rem; border-radius:0;
}
.models .mform input:focus{ outline:2px solid var(--ink); outline-offset:1px; }
.models .mform .btn{ flex:none; width:auto; padding:.55rem .9rem .48rem; letter-spacing:.18em; font-size:.66rem; }  /* the pages' .card .btn is full-width */
.models .mlist{ display:flex; flex-direction:column; gap:.3rem; }
.models .mlist.busy{ opacity:.55; pointer-events:none; }
.models .mrow{ display:flex; align-items:center; gap:.5rem; border:1px solid var(--hair); padding:.3rem .35rem .3rem .6rem; }
.models .mname{
  flex:1; min-width:0; text-align:left; background:none; border:0; padding:.15rem 0; cursor:pointer;
  font-family:var(--font-serif); font-size:.95rem; line-height:1.25; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
@media (hover: hover){ .models .mname:hover{ text-decoration:underline; } }
.models .mdate{ flex:none; font-family:var(--font-brand); font-size:.6rem; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-60); }
.models .mdel{
  flex:none; width:1.6rem; height:1.6rem; border:1px solid var(--hair); background:none; color:var(--ink);
  font-size:.95rem; line-height:1; cursor:pointer; padding:0;
}
.models .mdel.armed{ width:auto; padding:0 .45rem; font-family:var(--font-brand); font-size:.6rem; letter-spacing:.1em; text-transform:uppercase; background:var(--ink); color:var(--paper); border-color:var(--ink); }
@media (hover: hover){ .models .mdel:hover{ background:var(--ink); color:var(--paper); } }
@media (pointer: coarse){ .models .mdel{ min-width:36px; min-height:36px; } }

/* ── the header stays ────────────────────────────────────────────────────
   The masthead is pinned to the top of every page. At the top of a page it
   is the full centred masthead as before; once the page scrolls it draws in
   to a compact bar (navbar.js sets .stuck) so it keeps little of the screen.
   Under 960px the section links fold into a menu behind a button, while the
   Log in and theme buttons stay in view beside it. Classes are doubled to
   outrank each page's own single-class rules whichever order the sheets
   land in. */
.masthead-sentinel{ height:1px; margin-bottom:-1px; }
.masthead.masthead{ position:sticky; top:0; z-index:80; background:var(--paper); }
.masthead.masthead.stuck{ padding-top:.45rem; }
.masthead.masthead.stuck .brand{ font-size:1.35rem; }
.masthead.masthead.stuck .nav-row{ padding:.3rem 0 .45rem; }
html{ scroll-padding-top:5.2rem; }
/* the links keep their place in the row on wide screens; the wrapper is
   invisible to the layout until the narrow rules turn it into a panel */
.nav-menu{ display:contents; }
.nav-menu-btn{ display:none; }
@media (max-width:960px){
  /* Two lines. The brand has the first to itself, centred; the second
     carries the menu, Log in and theme buttons on the left and the follow
     links on the right. Where the second line cannot hold both, the links
     drop to a line of their own, still on the right. The break after the
     brand is the ::after, a full-width item of no height ordered between
     the brand and the rest, so the brand keeps its own width as a link. */
  .masthead.masthead{
    display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
    column-gap:.6rem; row-gap:0; padding:.6rem clamp(14px,2.5vw,48px) .65rem; text-align:left;
  }
  .masthead.masthead::after{ content:""; order:-1; flex:0 0 100%; height:0; }
  .masthead.masthead .brand{ order:-2; margin:0 auto; font-size:1.45rem; }
  .masthead.masthead.stuck{ padding-top:.6rem; }
  .masthead.masthead.stuck .brand{ font-size:1.45rem; }
  .nav-row.nav-row{ order:1; flex-direction:row; flex-wrap:nowrap; align-items:center; justify-content:flex-start; gap:.45rem; padding:0; flex:0 0 auto; margin:.6rem 0 0; }
  .masthead.masthead.stuck .nav-row{ padding:0; }
  .nav-row .nav-tools{ display:inline-flex; align-items:center; gap:.45rem; }
  /* the buttons at a size a thumb finds at once, all four 40px tall */
  .masthead.masthead .nav-menu-btn, .masthead.masthead .vn-auth-btn,
  .masthead.masthead .vn-auth-name, .masthead.masthead .theme-toggle{
    box-sizing:border-box; height:40px; min-height:0; font-size:.72rem; letter-spacing:.18em;
  }
  .masthead.masthead .nav-menu-btn, .masthead.masthead .theme-toggle{ padding:0 .65rem; }
  .masthead.masthead .vn-auth-btn, .masthead.masthead .vn-auth-name{ padding-top:0; padding-bottom:0; line-height:38px; }
  .masthead.masthead .vn-auth-btn, .masthead.masthead .vn-auth-pick{ padding-left:.65rem; padding-right:.65rem; }
  .masthead.masthead .theme-toggle .th-dot{ width:.8rem; height:.8rem; }
  /* signed in, the account button stands alone: it opens the account card,
     which carries Log out */
  .masthead.masthead .vn-auth-name + .vn-auth-btn{ display:none; }
  .nav-menu-btn{
    display:inline-flex; align-items:center; gap:.45rem;
    font-family:var(--font-brand); font-weight:500; font-size:.66rem; letter-spacing:.22em; text-transform:uppercase;
    color:var(--ink); background:none; border:1px solid var(--hair); cursor:pointer; padding:.28rem .6rem;
  }
  .nav-menu-btn .bars{ width:1rem; height:.75rem; position:relative; }
  .nav-menu-btn .bars::before, .nav-menu-btn .bars::after, .nav-menu-btn .bars i{
    content:""; position:absolute; left:0; right:0; height:1.5px; background:currentColor;
  }
  .nav-menu-btn .bars::before{ top:0; } .nav-menu-btn .bars i{ top:50%; margin-top:-.75px; } .nav-menu-btn .bars::after{ bottom:0; }
  .nav-menu-btn[aria-expanded="true"]{ background:var(--ink); color:var(--paper); }
  /* the folded sections: a panel under the bar, one link to a line */
  .nav-menu.nav-menu{
    display:none; position:absolute; left:0; right:0; top:100%;
    flex-direction:column; align-items:stretch; padding:.4rem 0 .6rem;
    background:var(--paper); border-top:1px solid var(--hair); border-bottom:1px solid var(--hair);
    box-shadow:0 14px 30px rgba(0,0,0,.22);
  }
  .masthead.menu-open .nav-menu.nav-menu{ display:flex; }
  .nav-menu.nav-menu a{ display:block; padding:.7rem clamp(14px,2.5vw,48px); border-bottom:1px solid color-mix(in srgb, var(--ink) 14%, transparent); }
  .nav-menu.nav-menu a:last-child{ border-bottom:0; }
  .nav-menu.nav-menu a[aria-current]{ border-bottom:1px solid color-mix(in srgb, var(--ink) 14%, transparent); padding-bottom:.7rem; font-weight:600; }
  .nav-row.nav-row .nav-menu a{ display:block; }
}
@media (max-width:480px){
  .masthead.masthead .theme-toggle #themeLbl{ display:none; }
  .masthead.masthead .theme-toggle{ width:40px; padding:0; justify-content:center; }
}
/* the same menu inside the app: a button in the bar opens the sections under it */
.vn-menu-btn{
  display:inline-flex; align-items:center; justify-content:center; width:40px; height:36px;
  background:none; border:0; color:var(--ink); cursor:pointer; padding:0;
}
.vn-menu-btn .bars{ width:18px; height:13px; position:relative; }
.vn-menu-btn .bars::before, .vn-menu-btn .bars::after, .vn-menu-btn .bars i{
  content:""; position:absolute; left:0; right:0; height:1.6px; background:currentColor;
}
.vn-menu-btn .bars::before{ top:0; } .vn-menu-btn .bars i{ top:50%; margin-top:-.8px; } .vn-menu-btn .bars::after{ bottom:0; }
.vn-menu{
  position:fixed; z-index:59; left:0; right:0; top:calc(var(--vn-top-inset, env(safe-area-inset-top)) + 44px);
  display:none; flex-direction:column; background:var(--paper);
  border-bottom:1px solid var(--ink); box-shadow:0 14px 30px rgba(0,0,0,.25);
  padding:.2rem 0 .4rem; max-height:calc(100vh - 44px - var(--vn-top-inset, env(safe-area-inset-top))); overflow:auto;
}
.vn-menu.open{ display:flex; }
.vn-menu a{
  display:block; padding:.85rem 1rem; text-decoration:none; color:var(--ink);
  font-family:var(--font-brand); font-weight:500; font-size:.74rem; letter-spacing:.3em; text-transform:uppercase;
  border-bottom:1px solid color-mix(in srgb, var(--ink) 14%, transparent);
}
.vn-menu a[aria-current]{ font-weight:600; }
.vn-menu a:last-child{ border-bottom:0; }

/* ── where to reach the maker ────────────────────────────────────────────
   navbar.js builds the same links twice for each place they can sit and
   these rules show one of the two: on the website, on the brand's line up
   to 960px and among the section links above it; in the app, in the top
   bar from 700px and at the foot of the sections menu below it. */
.vn-social{ display:inline-flex; align-items:center; gap:2px; }
/* each link keeps a 32px target but takes no more height in its line than
   the buttons beside it, so the masthead is no taller for carrying them */
.masthead .vn-social{ margin:-4px 0; }
.vn-social a{
  display:inline-flex; align-items:center; justify-content:center; flex:none;
  width:32px; height:32px; color:var(--ink); text-decoration:none;
  -webkit-tap-highlight-color:transparent;
}
.vn-social svg{ width:19px; height:19px; display:block; flex:none; }
@media (hover:hover){ .vn-social a:hover{ opacity:.55; } }
.vn-social a:focus-visible{ outline:1px solid var(--ink); outline-offset:1px; }
.masthead .vn-social-head{ display:none; }
@media (max-width:960px){
  .masthead .vn-social-head{ display:inline-flex; order:2; margin:.6rem 0 0 auto; }
  .masthead .vn-social-head a{ width:30px; height:40px; }
  .masthead .vn-social-head svg{ width:21px; height:21px; }
  .nav-row .vn-social-nav{ display:none; }
}
.nav-row .vn-social-nav a{ width:28px; }
@media (max-width:340px){ .masthead .vn-social a{ width:28px; } }
.vn-bar .vn-social-bar{ display:none; }
.vn-menu .vn-social-menu{ display:grid; grid-template-columns:repeat(2, max-content); gap:0 2.2rem; padding:.3rem 1rem .2rem; }
.vn-menu .vn-social-menu a{
  width:auto; height:auto; min-height:44px; padding:0; gap:.6rem; border-bottom:0; justify-content:flex-start;
  font-family:var(--font-brand); font-weight:500; font-size:.68rem; letter-spacing:.24em; text-transform:uppercase;
}
.vn-menu .vn-social-menu svg{ width:18px; height:18px; }
@media (min-width:700px){
  .vn-bar .vn-social-bar{ display:inline-flex; }
  .vn-menu .vn-social-menu{ display:none; }
  .vn-menu > a:last-of-type{ border-bottom:0; }
}
