/* Ben Zhou. One paper, one ink, six muted group colours (set in app.js), status as shapes. */
:root{
  --paper:#F2F0EA; --surface:#FBFAF7; --canvas:#E7E4DC; --ink:#1A1916; --ink2:#45423C; --ink3:#66625A;
  --line:#CFCABF; --rule:#E3DFD6; --wire:#A29D92;
  --sans:'Switzer', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --mono:'Martian Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --rmono:'Spline Sans Mono', ui-monospace, Menlo, monospace;
  --top:56px; --bar2:56px; --tabs:0px;
  --ease:cubic-bezier(.2,.7,.2,1);
}
*{box-sizing:border-box;margin:0}
/* phone: no grey flash on tap (each control has its own pressed state below) */
html{-webkit-text-size-adjust:100%;background:var(--paper);-webkit-tap-highlight-color:transparent}
/* the work browser, photo viewer, receipt and lightbox are app screens: no pull-to-refresh or page bounce behind them */
html:has(body.in-app,body.locked,dialog[open]){overscroll-behavior:none}
body{font:16px/1.5 var(--sans);color:var(--ink);background:var(--paper);-webkit-font-smoothing:antialiased;min-height:100dvh}
body.in-app,body.locked{overflow:hidden}
a{color:inherit;text-underline-offset:3px;text-decoration-thickness:1px}
button,select,input{font:inherit;color:inherit}
button{background:none;border:0;padding:0;cursor:pointer}
/* controls never double-tap-zoom, so the tap fires at once; a long press does not select a control's label */
a,button,select,label{touch-action:manipulation}
button,.btn,.brand,.views a,a.ib,.clink{user-select:none;-webkit-user-select:none}
.brand,.views a,a.ib{-webkit-touch-callout:none}
button:disabled{cursor:default;opacity:.35}
img{max-width:100%}
ul,ol{list-style:none;padding:0}
[hidden]{display:none !important}
/* text for readers without JavaScript (build-previews.mjs writes it); index.html sets .js in the head */
.js .static{display:none}
:focus-visible{outline:2px solid var(--ink);outline-offset:2px;border-radius:3px}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.mono{font-family:var(--mono);font-stretch:87.5%;font-size:12px}

/* shared bits */
.btn{display:inline-flex;flex-direction:column;justify-content:center;gap:1px;min-height:56px;padding:8px 18px;border:1.5px solid var(--ink);border-radius:6px;text-decoration:none;background:var(--surface);transition:background-color .15s,color .15s}
.btn .b-main{font-weight:600;font-size:17px;line-height:1.25}
.btn .b-sub{font:400 11px/1.4 var(--mono);font-stretch:87.5%;color:var(--ink3);display:flex;align-items:center;gap:10px}
.btn.primary{background:var(--ink);color:var(--surface)}
.btn.primary .b-sub{color:#C9C5BB}
@media (hover:hover) and (pointer:fine){.btn:hover{background:var(--rule)}}
@media (hover:hover) and (pointer:fine){.btn.primary:hover{background:#34322D}}
.btn.small{min-height:44px;padding:0 14px;flex-direction:row;align-items:center;gap:6px;font-size:15px;font-weight:500;border-width:1px}
.btn:active{transform:translateY(1px)}
.sw{display:inline-block;flex:none;width:10px;height:10px;border-radius:2px;background:var(--k)}
.sw.ph{background:none;border:1.5px solid var(--ink3)}
/* status: a shape in ink, never a colour */
.st{display:inline-block;flex:none;width:9px;height:9px;border-radius:50%;border:1.5px solid var(--ink);vertical-align:-.5px}
.st-live{background:var(--ink)}
.st-building{background:linear-gradient(90deg,var(--ink) 50%,transparent 50%)}
.st-design{border-style:dashed}
.st-shipped{border-radius:1px;background:var(--ink);width:8px;height:8px}
.stt{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.cover{display:block;position:relative;width:100%;height:100%;background:color-mix(in srgb,var(--k) 13%,var(--surface));overflow:hidden}
.cover svg{position:absolute;left:18%;top:12%;width:64%;height:76%;fill:none;stroke:var(--k);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.seg{display:inline-flex;background:var(--surface);border:1px solid var(--line);border-radius:8px;padding:3px;gap:2px}
.seg button{min-height:36px;padding:0 12px;border-radius:5px;font-size:14px;font-weight:500;color:var(--ink2);white-space:nowrap}
.seg button[aria-pressed="true"]{background:var(--ink);color:var(--surface)}
@media (hover:hover) and (pointer:fine){.seg button:not([aria-pressed="true"]):hover{background:var(--rule)}}
.ib{min-width:44px;min-height:40px;padding:0 12px;border:1px solid var(--line);border-radius:6px;background:var(--surface);font-size:15px;font-weight:500}
@media (hover:hover) and (pointer:fine){.ib:not(:disabled):hover{background:var(--rule)}}
.ib[aria-pressed="true"]{background:var(--ink);color:var(--surface);border-color:var(--ink)}
.empty{padding:40px 20px;text-align:center;color:var(--ink2);display:flex;flex-direction:column;align-items:center;gap:14px}
.vnote{font-size:14px;color:var(--ink3)}
.wl{display:flex;align-items:baseline;gap:7px;font-size:14px;line-height:1.4;color:var(--ink2)}
.wl i{flex:none;width:16px;border-top:1.5px solid var(--ink3);transform:translateY(-4px)}
.wl.idea i{border-top-style:dashed}
.wl b{font-weight:600;color:var(--ink)}

/* ============ landing ============ */
/* Phone layout: (max-width:760px), or a phone on its side, (max-height:500px) and (max-width:960px). app.js phoneMQ and
   assets/map/map.css use the same test; check.mjs asserts they agree. */
.landing{min-height:100dvh;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.82fr);gap:0;padding:0}
.l-text{container-type:inline-size;display:flex;flex-direction:column;justify-content:center;padding:48px clamp(24px,6vw,96px);padding-left:max(clamp(24px,6vw,96px),env(safe-area-inset-left));order:1}
.l-photo{order:2;position:relative;margin:0;height:100dvh;overflow:hidden;background:#2a2926}
.l-photo img{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover;object-position:50% 50%;transition:opacity .7s ease}
.l-photo img[aria-hidden="true"]{opacity:0}
/* The caption and Pause sit on the photograph. A dark plate behind each keeps them at 4.5:1 or better on the brightest picture
   (white under the plate gives 5.3:1); without it they measured about 1.1:1 on the neon and the white car (2026-10-07). */
.l-photo figcaption{position:absolute;left:11px;bottom:10px;padding:4px 5px;background:rgb(18 17 15 / .68);font:400 11px/1 var(--mono);font-stretch:87.5%;color:#EDEAE3;text-shadow:0 1px 2px rgb(0 0 0 / .5)}
.l-pause{position:absolute;right:max(6px,env(safe-area-inset-right));bottom:0;min-width:44px;min-height:40px;padding:0 10px;background:linear-gradient(rgb(18 17 15 / .68) 0 0) center / calc(100% - 10px) 19px no-repeat;font:400 11px/1 var(--mono);font-stretch:87.5%;color:#EDEAE3;text-shadow:0 1px 2px rgb(0 0 0 / .5)}
@media (hover:hover) and (pointer:fine){.l-pause:hover{text-decoration:underline}}
.l-kicker{font:500 12px/1 var(--mono);font-stretch:87.5%;letter-spacing:.08em;text-transform:uppercase;color:var(--ink3)}
.landing h1{font-size:clamp(72px,9.4vw,152px);line-height:.9;font-weight:800;letter-spacing:-.05em;margin:14px 0 22px;margin-left:-.04em}
.l-lede{font-size:clamp(18px,1.5vw,21px);line-height:1.45;max-width:31em;color:var(--ink2)}
.l-cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:32px}
/* landing-cta: "See the work" is as wide as its label plus padding, like Resume beside it, instead of a fixed 260px with the label on the left. */
@media (min-width:761px){.l-cta .btn{padding-inline:28px}}
.dots6{display:inline-flex;gap:3px}
.dots6 i{width:7px;height:7px;border-radius:1.5px;background:var(--k)}
.btn.primary .dots6 i{box-shadow:0 0 0 1px rgb(255 255 255 / .12)}
.l-contact{display:grid;grid-template-columns:repeat(4,auto);justify-content:start;gap:4px 28px;margin-top:30px}
.l-contact a{display:flex;flex-direction:column;justify-content:center;min-height:48px;text-decoration:none;font-size:15px;font-weight:500}
.l-contact a span{font:400 11px/1.5 var(--mono);font-stretch:87.5%;color:var(--ink3);text-transform:uppercase;letter-spacing:.06em}
.l-contact .contact-link{font-weight:500;text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:4px}
@media (hover:hover) and (pointer:fine){.l-contact a:hover .contact-link{color:var(--ink);text-decoration-color:var(--ink)}}
.l-more{align-self:flex-start;margin-top:22px;min-height:44px;font-size:15px;color:var(--ink2);text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:4px}
a.l-more{display:inline-flex;align-items:center;gap:6px}
.l-card+.l-more{margin-top:0}
@media (hover:hover) and (pointer:fine){.l-more:hover{color:var(--ink)}}

/* about */
.about{max-width:1080px;margin:0 auto;padding:80px max(clamp(24px,6vw,96px),env(safe-area-inset-right)) 40px max(clamp(24px,6vw,96px),env(safe-area-inset-left))}
#home{border:0}
.about h2{font-size:15px;font-weight:600;font-family:var(--mono);font-stretch:87.5%;text-transform:uppercase;letter-spacing:.08em;color:var(--ink3);margin-bottom:28px}
.cv{display:grid;grid-template-columns:180px minmax(0,1fr);gap:0 40px}
.cv dt{font-weight:700;font-size:17px;padding:18px 0;border-top:1px solid var(--rule)}
.cv dd{padding:18px 0;border-top:1px solid var(--rule);color:var(--ink2);max-width:62ch}
.cv dd b{color:var(--ink);font-weight:600}
.cv dd p+p{margin-top:14px}
.cv .when{display:block;font:400 12px/1.8 var(--mono);font-stretch:87.5%;color:var(--ink3)}
.cv .role{display:flex;align-items:center;gap:16px}
.cv .role .orglogo{flex:0 0 60px;width:60px;height:26px;object-fit:contain;object-position:left center}
.cv .nums{display:flex;gap:28px;flex-wrap:wrap}
.cv .nums b{font-size:32px;font-weight:800;letter-spacing:-.03em;margin-right:6px}
.foot{display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px 20px;margin-top:60px;padding:18px 0 max(18px,env(safe-area-inset-bottom));border-top:1px solid var(--line);font-size:14px;color:var(--ink3)}
/* edge-alignment: one left and right edge per page. The footer rule on About, Privacy and Terms ends where the text column ends,
   back links and CASE links lose their 4px inset, and the header and filter bar start at 20px like the views under them (they were at 16). */
.foot{font-size:16px;max-width:calc(220px + 62ch)}
.foot p{font-size:14px}
.clink.clink{padding-inline:0}
@media (min-width:761px){#app .top,#app .bar2{padding-inline:max(20px,env(safe-area-inset-left)) max(20px,env(safe-area-inset-right))}}

@media (max-width:760px),(max-height:500px) and (max-width:960px){
  .landing{grid-template-columns:1fr;grid-template-rows:auto 1fr;min-height:100svh}
  .l-photo{order:0;height:clamp(120px,27svh,240px)}
  .l-photo img{object-position:18% 24%}
  .l-photo figcaption{left:auto;right:7px;bottom:6px}
  .l-pause{right:auto;left:2px;bottom:-5px}
  .l-text{justify-content:flex-start;padding:22px 20px max(16px,env(safe-area-inset-bottom))}
  .landing h1{font-size:clamp(64px,19vw,84px);margin:8px 0 12px}
  .l-lede{font-size:17px}
  .l-cta{display:grid;grid-template-columns:1fr;gap:10px;margin-top:20px}
  .l-cta .btn{min-height:56px;width:100%}
  .l-cta .btn.primary{min-width:0}
  .l-contact{grid-template-columns:1fr 1fr;gap:0 16px;margin-top:14px}
  .l-contact a{min-height:50px;font-size:15px;overflow-wrap:anywhere}
  /* the university address (196px) is wider than half a phone, so it takes a row of its own; under 344px of room the Gmail one (163px) does too */
  .l-contact li:first-child{grid-column:1/-1}
  @container (max-width:343px){.l-contact li:nth-child(2){grid-column:1/-1}}
  .l-more{margin-top:6px}
  .about{padding:48px 20px 20px}
  .cv{grid-template-columns:1fr}
  .cv .role{gap:12px}
  .cv .role .orglogo{flex-basis:40px;width:40px;height:22px}
  .cv dt{padding:18px 0 4px}
  .cv dd{border-top:0;padding:0 0 18px}
}
/* Beside the photo the contact list takes as many columns as its longest lines fit without breaking: the two
   emails need 400px, a third column 530px, all four 656px (15.5px Switzer), each with 10px to spare. */
@media (min-width:761px) and (min-height:501px),(min-width:961px){
  .l-contact{grid-template-columns:auto}
  .l-contact .contact-link{white-space:nowrap}
  @container (min-width:410px){.l-contact{grid-template-columns:repeat(2,auto)}}
  @container (min-width:540px){.l-contact{grid-template-columns:repeat(3,auto)}}
  @container (min-width:666px){.l-contact{grid-template-columns:repeat(4,auto)}}
}
@media (max-width:760px) and (max-height:700px){
  .l-photo{height:148px}
  .landing h1{font-size:60px}
  .l-kicker{display:none}
}

/* ============ work browser ============ */
#app{position:fixed;inset:0;display:grid;grid-template-rows:var(--top) auto minmax(0,1fr);background:var(--paper)}
.top{display:flex;align-items:center;gap:16px;padding:0 max(16px,env(safe-area-inset-right)) 0 max(16px,env(safe-area-inset-left));border-bottom:1px solid var(--line);background:var(--paper);z-index:20}
.brand{gap:7px;font-weight:700;font-size:17px;letter-spacing:-.01em;text-decoration:none;min-height:44px;display:flex;align-items:center;white-space:nowrap}
.views{display:flex;gap:2px;margin:0 auto;background:var(--surface);border:1px solid var(--line);border-radius:8px;padding:3px}
.views a{display:flex;align-items:center;gap:7px;min-height:36px;padding:0 14px;border-radius:5px;text-decoration:none;font-size:15px;font-weight:500;color:var(--ink2)}
@media (hover:hover) and (pointer:fine){.views a:hover{background:var(--rule)}}
.views a[aria-current="page"]{background:var(--ink);color:var(--surface)}
.views svg,.act svg,.search svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.5;flex:none}
.acts{display:flex;gap:4px}
.act{display:flex;align-items:center;gap:6px;min-height:44px;min-width:44px;justify-content:center;padding:0 10px;border-radius:6px;font-size:15px;font-weight:500;position:relative}
.act[aria-expanded="true"]{background:var(--rule)}
@media (hover:hover) and (pointer:fine){.act:hover{background:var(--rule)}}
.act .cnt{min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:var(--ink);color:var(--surface);font-size:11px;line-height:18px;font-weight:600}
/* header-centre: the view switcher sits on the page's centre line and stays there when the Filter count appears; the count gets a gap from the word. */
.act .cnt{margin-left:6px}
@media (min-width:761px) and (min-height:501px),(min-width:961px){
  #app .top{display:grid;grid-template-columns:minmax(max-content,1fr) auto minmax(max-content,1fr)}
  .top .brand{justify-self:start}
  #app .top .views{margin:0}
  .top .acts{justify-self:end}
}
#searchBtn{display:none}
.bar2{display:flex;align-items:center;gap:14px;min-height:var(--bar2);padding:8px max(16px,env(safe-area-inset-right)) 8px max(16px,env(safe-area-inset-left));border-bottom:1px solid var(--line);background:var(--paper);z-index:15}
.search{display:flex;align-items:center;gap:8px;height:40px;padding:0 10px;border:1px solid var(--line);border-radius:6px;background:var(--surface);width:250px;flex:none;color:var(--ink3)}
.search:focus-within{border-color:var(--ink);box-shadow:0 0 0 1px var(--ink)}
.search input{flex:1;min-width:0;border:0;background:none;outline:none;font-size:16px;color:var(--ink)}
.search input::-webkit-search-cancel-button{-webkit-appearance:none}
.search kbd{font:400 11px/1 var(--mono);border:1px solid var(--line);border-radius:3px;padding:3px 5px;color:var(--ink3)}
.filters{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.fchip{display:inline-flex;align-items:center;gap:7px;min-height:36px;padding:0 11px;border:1px solid var(--line);border-radius:6px;background:var(--surface);font-size:14px;font-weight:500;white-space:nowrap}
.fchip small{font:400 11px/1 var(--mono);color:var(--ink3)}
@media (hover:hover) and (pointer:fine){.fchip:hover{border-color:var(--ink3)}}
.fchip[aria-pressed="true"]{border-color:var(--k);background:color-mix(in srgb,var(--k) 12%,var(--surface));box-shadow:inset 0 0 0 1px var(--k)}
.fclear{min-height:36px;padding:0 10px;font-size:14px;text-decoration:underline;text-underline-offset:3px;color:var(--ink2)}
.count{margin-left:auto;font:400 12px/1 var(--mono);font-stretch:87.5%;color:var(--ink3);white-space:nowrap}
body[data-view="photos"] .filters{display:none}
.top{grid-row:1}.bar2{grid-row:2}
.stage-wrap{grid-row:3;position:relative;overflow:hidden}
.view{position:absolute;inset:0;overflow:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;padding:0 env(safe-area-inset-right) 0 env(safe-area-inset-left)}
.vhead{display:flex;align-items:center;flex-wrap:wrap;gap:10px 14px;padding:16px 20px}
.mt{font-size:26px;font-weight:700;letter-spacing:-.02em;margin-right:auto}
.mt span{color:var(--ink3);font-weight:500}
.pager{display:flex;gap:6px}

/* ---- canvas ---- */
#v-canvas{overflow:hidden;background:var(--canvas);padding:0}
.stage{position:absolute;inset:0;overflow:hidden;touch-action:none;cursor:grab;outline:none}
.stage:focus-visible{outline:2px solid var(--ink);outline-offset:-2px}
.stage.panning{cursor:grabbing}
.world{position:absolute;left:0;top:0;transform-origin:0 0;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;--z:1}
.wires{position:absolute;left:0;top:0;width:1px;height:1px;overflow:visible;pointer-events:none}
.wires path{fill:none;stroke:var(--wire);stroke-width:1.25}
.wires path.idea{stroke-dasharray:5 4}
.wires circle{fill:var(--surface);stroke:var(--wire);stroke-width:1.25}
.wires .hot{stroke:var(--ink);stroke-width:2}
.wires circle.hot{fill:var(--ink)}
.wires .dim{opacity:.18}
.frame{position:absolute;border:1px dashed color-mix(in srgb,var(--k) 45%,transparent);border-radius:12px;background:color-mix(in srgb,var(--k) 5%,transparent);pointer-events:none}
.flabel{position:absolute;left:0;bottom:100%;padding:0 0 8px 2px;width:max-content;max-width:calc(510px * var(--z) - 6px);line-height:1.15;transform-origin:0 100%;transform:scale(calc(1 / var(--z)));font-weight:700;font-size:15px;color:var(--k)}
.flabel b{margin-left:8px;font:400 12px/1 var(--mono);color:var(--ink3)}
.frame.dim{opacity:.35}
.node{position:absolute;display:block;text-align:left;background:var(--surface);border:1px solid var(--line);border-radius:7px;cursor:pointer;transition:opacity .2s}
.nh{display:flex;align-items:center;gap:9px;height:40px;padding:0 12px;background:color-mix(in srgb,var(--k) 13%,var(--surface));border-bottom:1px solid color-mix(in srgb,var(--k) 22%,var(--line));border-radius:6px 6px 0 0}
.nt{flex:1;min-width:0;font-size:16px;font-weight:650;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nimg{display:block;width:100%;height:auto;aspect-ratio:16/10;object-fit:cover;object-position:top;border-bottom:1px solid var(--rule);background:var(--rule)}
.nb{display:grid;gap:6px;padding:11px 14px 13px}
.nd,.ns{font:400 11px/1.5 var(--mono);font-stretch:87.5%;color:var(--ink3)}
.nbl{font-size:14px;line-height:1.45;color:var(--ink2)}
.node.lit,.node.hot{border-color:var(--k);box-shadow:0 0 0 1px var(--k)}
@media (hover:hover) and (pointer:fine){.node:hover{border-color:var(--k);box-shadow:0 0 0 1px var(--k)}}
.node.dim{opacity:.2}
.far{display:none;position:absolute;left:0;right:0;top:0;padding:4px 0 0 6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:650;line-height:1.1;pointer-events:none;z-index:1}
.world.out .far{display:block}
.world.deep .node{background:color-mix(in srgb,var(--k) 13%,var(--surface))}
.world.deep .nb,.world.deep .nh{visibility:hidden}
.world.deep .far{padding-top:6px}
.world.out .nh .nt,.world.out .nh .sw{visibility:hidden}
/* the chip shrinks with the canvas; its tap area grows to stay 24px tall on screen, stopping halfway to the next chip
   (--gy) and at the project beside it (--gx), both set in layoutCanvas, so no two tap areas overlap at any zoom */
.tech::after{--grow:max(0px,12px / var(--z) - 15px);content:"";position:absolute;inset:calc(-1 * min(var(--gy,999px),var(--grow))) calc(-1 * min(var(--gx,999px),var(--grow)))}
.tech{position:absolute;display:flex;align-items:center;gap:7px;height:30px;padding:0 10px;background:var(--surface);border:1px solid var(--ink3);border-radius:4px;font:500 11px/1 var(--mono);font-stretch:87.5%;white-space:nowrap;cursor:pointer;transition:opacity .2s}
.tech .k{width:7px;height:7px;border:1.5px solid var(--ink);background:var(--ink)}
.tech.idea{border-style:dashed}
.tech.idea .k{border-radius:50%;background:none}
.tech small{font-size:11px;color:var(--ink3)}
.tech.hot,.tech.lit{border-color:var(--ink);box-shadow:0 0 0 1px var(--ink)}
@media (hover:hover) and (pointer:fine){.tech:hover{border-color:var(--ink);box-shadow:0 0 0 1px var(--ink)}}
.tech.dim{opacity:.25}
.hud{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);display:flex;gap:8px;z-index:5}
.zoom{display:flex;background:var(--surface);border:1px solid var(--line);border-radius:8px;padding:3px;gap:2px}
.zoom button{min-width:40px;min-height:36px;padding:0 10px;border-radius:5px;font-size:15px;font-weight:500}
@media (hover:hover) and (pointer:fine){.zoom button:hover{background:var(--rule)}}
.mini{position:absolute;left:max(14px,env(safe-area-inset-left));bottom:14px;width:190px;height:110px;background:var(--surface);border:1px solid var(--line);border-radius:6px;z-index:4;cursor:crosshair;touch-action:none}
.mini rect{opacity:.75}
.mini rect.t{fill:var(--ink3);opacity:.6}
.mini rect.dim{opacity:.15}
.mini .view{fill:rgba(26,25,22,.06);stroke:var(--ink);stroke-width:1.5;vector-effect:non-scaling-stroke;opacity:1}
/* ---- calendar: phone month ---- */
.cal-m{max-width:640px;margin:0 auto;padding-bottom:24px}
.mgrid{padding:0 12px;touch-action:pan-y}
.dows{display:grid;grid-template-columns:repeat(7,1fr);font:500 11px/28px var(--mono);color:var(--ink3);text-align:center}
.wk{position:relative;display:grid;grid-template-columns:repeat(7,1fr);height:calc(44px + var(--dt) + var(--lanes) * 24px);border-top:1px solid var(--rule)}
.day{position:relative;display:flex;justify-content:center;padding-top:4px;font-size:15px;font-variant-numeric:tabular-nums}
.day span{min-width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px}
.day.o{color:#716D64}
.day.t span{background:var(--ink);color:var(--surface);font-weight:600}
.cd{display:flex;flex-wrap:wrap;justify-content:center;align-content:flex-start;gap:2px}
.cd i{position:relative;width:5px;height:5px;border-radius:50%;background:var(--k);cursor:pointer}
.cd{position:relative;cursor:pointer}
.cd::before{content:"";position:absolute;left:50%;top:50%;width:max(100%,24px);height:max(100%,24px);transform:translate(-50%,-50%)}
.day .cd{position:absolute;top:36px;left:0;right:0;max-width:40px;margin:0 auto}
.pdays .cd{padding:2px 0 4px}
.ev{position:absolute;left:calc(var(--c0) * 100% / 7 + 2px);width:calc(var(--n) * 100% / 7 - 4px);top:calc(38px + var(--dt) + var(--ln) * 24px);height:18px;border-radius:3px;background:var(--k);color:#fff;font-size:12px;font-weight:600;line-height:18px;padding:0 5px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ev.l{left:calc(var(--c0) * 100% / 7);width:calc(var(--n) * 100% / 7 - 2px);border-radius:0 3px 3px 0}
.ev.r{width:calc(var(--n) * 100% / 7 - 2px);border-radius:3px 0 0 3px}
.ev.l.r{width:calc(var(--n) * 100% / 7);border-radius:0}
.ev::after{content:"";position:absolute;inset:-3px 0}
.ag-h{font-size:14px;font-weight:600;font-family:var(--mono);font-stretch:87.5%;text-transform:uppercase;letter-spacing:.06em;color:var(--ink3);padding:22px 20px 6px;border-top:1px solid var(--line);margin-top:8px}
.agenda{padding:0 12px}
.ag{display:grid;grid-template-columns:52px minmax(0,1fr);gap:12px;width:100%;text-align:left;padding:12px 8px;border-bottom:1px solid var(--rule);border-radius:4px}
@media (hover:hover) and (pointer:fine){.ag:hover{background:var(--rule)}}
.ag-d b{display:block;font-size:24px;font-weight:700;line-height:1.1;letter-spacing:-.02em}
.ag-d small{font:400 11px/1.4 var(--mono);color:var(--ink3);text-transform:uppercase}
.ag-m{display:grid;gap:2px}
.ag-n{display:flex;align-items:center;gap:8px;font-size:17px;font-weight:600}
.ag-w{font-size:14px;color:var(--ink2)}
.ag-s{font-size:14px;color:var(--ink3)}

/* ---- calendar: desktop year planner ---- */
.planner{padding:0 20px 40px}
.planner .vhead{padding:16px 0}
.planner .vnote{flex-basis:100%;margin-top:-4px}
.psheet{border-top:2px solid var(--ink);border-bottom:1px solid var(--ink3);min-width:900px}
.ph-row{display:grid;grid-template-columns:52px minmax(0,1fr) 270px;column-gap:14px;border-top:1px solid var(--rule)}
.ph-row.head{border-top:0}
.ph-row.future{opacity:.55}
.pm{font-size:19px;font-weight:700;padding-top:4px;letter-spacing:-.01em}
.pdays{display:grid;grid-template-columns:repeat(37,minmax(0,1fr));grid-template-rows:20px repeat(var(--lanes),20px) minmax(8px,auto);row-gap:4px;border-right:1px solid var(--rule)}
.head .pdays{grid-template-rows:24px;border-right:0}
.head .pdays span{font:500 11px/24px var(--mono);text-align:center;color:var(--ink3)}
.head .pdays span.we{color:var(--ink)}
.pn-h{font:500 11px/24px var(--mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink3)}
.c{grid-row:1/-1;border-left:1px solid var(--rule)}
.c.we{background:rgb(26 25 22 / .045)}
.c.x{background:repeating-linear-gradient(135deg,transparent 0 4px,rgb(26 25 22 / .04) 4px 5px)}
.dn{display:block;margin:2px auto 0;width:18px;height:16px;text-align:center;font:400 11px/16px var(--mono);color:var(--ink3);font-variant-numeric:tabular-nums}
.dn.today{background:var(--ink);color:var(--surface);border-radius:8px;font-weight:500}
.pbar{position:relative;z-index:1;margin:0 1px;min-width:0;background:var(--k);color:#fff;border-radius:3px;text-align:left;overflow:hidden}
.pbar span{display:block;padding:0 6px;font-size:12px;font-weight:600;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pbar.cl{margin-left:0;border-radius:0 3px 3px 0}
.pbar.cr{margin-right:0;border-radius:3px 0 0 3px}
.pbar.now{border-radius:3px 0 0 3px;clip-path:polygon(0 0,calc(100% - 7px) 0,100% 50%,calc(100% - 7px) 100%,0 100%)}
.pbar.cl.now{border-radius:0}
@media (hover:hover) and (pointer:fine){.pbar:hover{filter:brightness(1.15)}}
.tl{justify-self:center;width:2px;background:var(--ink);z-index:2}
.pnotes{padding:4px 0 8px}
.pnotes button{display:flex;align-items:center;gap:8px;width:100%;min-height:26px;text-align:left;font-size:14px;padding:0 4px;border-radius:3px}
@media (hover:hover) and (pointer:fine){.pnotes button:hover{background:var(--rule)}}
.pn{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd{margin-left:auto;font:400 11px/1 var(--mono);font-stretch:87.5%;color:var(--ink3);white-space:nowrap}
.heat{width:max-content;margin:20px auto 22px}
.heat-head{display:flex;justify-content:space-between;gap:16px;align-items:baseline;margin-bottom:8px}
.heat-head h3{font-size:15px;font-weight:700}
.heat-head p{font:400 11px/1.4 var(--mono);font-stretch:87.5%;color:var(--ink3)}
.heat-grid{display:grid;grid-auto-flow:column;grid-template-columns:repeat(9,10px);grid-template-rows:repeat(7,10px);gap:3px}
.heat-grid i,.heat-key i{display:block;border-radius:2px;background:var(--rule)}
.heat-grid .h1,.heat-key .h1{background:color-mix(in srgb,var(--ink) 20%,var(--surface))}
.heat-grid .h2,.heat-key .h2{background:color-mix(in srgb,var(--ink) 42%,var(--surface))}
.heat-grid .h3,.heat-key .h3{background:color-mix(in srgb,var(--ink) 68%,var(--surface))}
.heat-grid .h4,.heat-key .h4{background:var(--ink)}
.heat-key{display:flex;align-items:center;justify-content:flex-end;gap:4px;margin-top:8px;font:400 11px/1 var(--mono);font-stretch:87.5%;color:var(--ink3)}
.heat-key i{width:10px;height:10px}
.planner-body{display:grid;grid-template-columns:126px minmax(900px,1fr);gap:16px;align-items:start;min-width:1042px}
.planner-body>.heat{position:sticky;top:16px;margin:0;padding-top:4px}
.planner-body .heat-head{display:block;margin-bottom:10px}
.planner-body .heat-head p{margin-top:3px}
.planner-body .heat-key{justify-content:flex-start;flex-wrap:wrap;margin-top:10px}

/* ---- table ---- */
.tab .vhead{position:sticky;left:0}
.tscroll{overflow-x:auto;padding:0 20px 40px}
table{border-collapse:separate;border-spacing:0;width:100%;min-width:880px;font-size:15px}
thead th{position:sticky;top:0;background:var(--paper);z-index:2;text-align:left;border-bottom:1.5px solid var(--ink);padding:0}
thead th button{display:flex;align-items:center;gap:6px;width:100%;min-height:40px;padding:0 10px;font:500 11px/1 var(--mono);font-stretch:87.5%;text-transform:uppercase;letter-spacing:.06em;color:var(--ink3)}
th[aria-sort="ascending"] button,th[aria-sort="descending"] button{color:var(--ink)}
@media (hover:hover) and (pointer:fine){thead th button:hover{color:var(--ink)}}
th[aria-sort="ascending"] i::after{content:"\2191"}
th[aria-sort="descending"] i::after{content:"\2193"}
tbody th,tbody td{padding:8px 10px;border-bottom:1px solid var(--rule);text-align:left;font-weight:400;vertical-align:middle}
tbody tr{cursor:pointer}
@media (hover:hover) and (pointer:fine){tbody tr:hover{background:var(--surface)}}
.rowbtn{display:block;text-align:left;width:100%;min-height:36px}
.tn{display:flex;align-items:center;gap:12px;font-weight:600}
.tth{flex:none;display:block;width:48px;height:30px;border-radius:3px;overflow:hidden;background:var(--rule)}
.tth img,img.tth{display:block;width:48px;height:30px;object-fit:cover}
/* table-thumbs: the table's screenshots at twice the size (96 by 60 instead of 48 by 30). The phone list keeps its
   64px pictures, because a wider one squeezes the text beside it into more lines. */
.tth,.tth img,img.tth{width:96px;height:60px}
.tth img{object-position:top}
.tn{gap:16px}
.tk{display:inline-flex;align-items:center;gap:8px;white-space:nowrap}
td .mono{white-space:nowrap}
.sortsel{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--ink3)}
.sortsel select{min-height:40px;padding:0 10px;border:1px solid var(--line);border-radius:6px;background:var(--surface);font-size:16px;color:var(--ink)}
.cards{padding:0 12px 24px}
.cards li{position:relative}
.card-case{position:absolute;right:6px;top:8px}
.cards .card{padding-right:72px}
.card{display:grid;grid-template-columns:64px minmax(0,1fr);gap:14px;width:100%;text-align:left;padding:12px 6px;border-bottom:1px solid var(--rule)}
.c-th{display:block;width:64px;height:64px;border-radius:4px;overflow:hidden;background:var(--rule)}
.c-th img{display:block;width:100%;height:100%;object-fit:cover;object-position:top}
/* wrap-orphans: no single word or arrow is left alone on a last line: "8 days so far" and a link's arrow stay together,
   and blurbs wrap without a one-word last line. */
.nw{white-space:nowrap}
.c-blurb,.c-txt,.d-desc,.l-lede{text-wrap:pretty}
.c-m{display:grid;gap:2px;min-width:0}
.c-n{font-size:17px;font-weight:600}
.c-k{display:flex;align-items:center;gap:7px;font-size:14px;color:var(--ink2);flex-wrap:wrap}
.c-d{font-size:14px;color:var(--ink2)}
.c-s{font:400 11px/1.5 var(--mono);font-stretch:87.5%;color:var(--ink3)}

/* ---- photos ---- */
.photos{padding-bottom:32px}
.pgrid{columns:4 240px;column-gap:10px;padding:0 20px}
.pgrid li{break-inside:avoid;margin-bottom:10px}
.pgrid button{display:block;width:100%;border-radius:2px;overflow:hidden;background:#2a2926}
.pgrid img{display:block;width:100%;height:auto;transition:opacity .2s}
@media (hover:hover) and (pointer:fine){.pgrid button:hover img{opacity:.88}}


/* ---- detail: side panel on desktop, full sheet on phone ---- */
.detail{position:fixed;z-index:30;top:calc(var(--top) + var(--bar2));right:0;bottom:0;width:min(440px,42vw);background:var(--surface);border-left:1px solid var(--ink3);box-shadow:-12px 0 28px -20px rgb(0 0 0 / .35);overflow-y:auto;overscroll-behavior:contain;padding-right:env(safe-area-inset-right)}
.d-bar{position:sticky;top:0;z-index:2;display:flex;align-items:center;gap:6px;padding:10px 14px;background:var(--surface);border-bottom:1px solid var(--rule)}
.d-pos{font:400 12px/1 var(--mono);color:var(--ink3);margin-left:4px}
.d-x{margin-left:auto}
.d-case{margin-left:auto;display:inline-flex;align-items:center;text-decoration:none}
.d-case+.d-x{margin-left:0}
.d-body{padding:18px 22px 40px}
.d-media{aspect-ratio:16/10;border-radius:5px;overflow:hidden;background:var(--rule);border:1px solid var(--rule)}
.d-media img{display:block;width:100%;height:100%;object-fit:contain;background:#fff}
.d-th{display:flex;gap:8px;margin-top:8px;overflow-x:auto;padding-bottom:4px;scrollbar-width:thin}
.d-th button{flex:none;width:64px;height:40px;border-radius:3px;overflow:hidden;border:1.5px solid transparent}
.d-th button[aria-pressed="true"]{border-color:var(--ink)}
.d-th img{width:100%;height:100%;object-fit:cover;display:block}
.d-videos{display:grid;gap:10px;margin-top:12px}
.d-videos iframe{display:block;width:100%;aspect-ratio:16/9;border:0;border-radius:5px;background:#111}
.d-kind{display:flex;align-items:center;gap:8px;margin-top:18px;font-size:14px;font-weight:600;color:var(--k)}
.d-kind .stt{color:var(--ink2);font-weight:500}
.d-sep{color:var(--line)}
.detail h2{font-size:30px;line-height:1.1;font-weight:800;letter-spacing:-.03em;margin:6px 0 6px}
.d-when{font:400 12px/1.5 var(--mono);font-stretch:87.5%;color:var(--ink3)}
.d-desc{margin-top:14px;font-size:17px;line-height:1.55;color:var(--ink2)}
.d-links{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
.d-none{margin-top:16px;font-size:15px;color:var(--ink3)}
.d-dl{display:grid;grid-template-columns:72px minmax(0,1fr);gap:10px 14px;margin-top:24px;padding-top:18px;border-top:1px solid var(--rule);font-size:15px}
.d-dl dt{font:500 11px/2.1 var(--mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink3)}
.d-dl dd{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.d-dl dd.d-sh{display:grid;gap:6px}
.chip{min-height:32px;padding:0 10px;border:1px solid var(--line);border-radius:5px;font:400 12px/1 var(--mono);font-stretch:87.5%}
@media (hover:hover) and (pointer:fine){.chip:hover{border-color:var(--ink)}}
.lnk{text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px;min-height:28px}
@media (hover:hover) and (pointer:fine){.lnk:hover{text-decoration-color:var(--ink)}}

/* ---- photo viewer ---- */
/* the viewer reads swipes itself (sideways steps, down closes), so the browser keeps only pinch-zoom */
/* a flex column, not a grid: Safari sizes a picture's height:100% from the whole viewer instead of its row, so the picture ran under the caption and buttons */
.viewer{touch-action:pinch-zoom;position:fixed;inset:0;z-index:60;background:#121211;display:flex;flex-direction:column;color:#ECE9E2}
.viewer img{flex:1 1 0;min-height:0;width:100%;height:auto;object-fit:contain;padding:max(12px,env(safe-area-inset-top)) 12px 0}
.v-bar{display:flex;align-items:center;gap:8px;padding:10px max(14px,env(safe-area-inset-right)) max(12px,env(safe-area-inset-bottom)) max(14px,env(safe-area-inset-left))}
.v-bar p{flex:1;min-width:0;font-size:15px;line-height:1.35}
.v-bar p span{display:block;font:400 11px/1.6 var(--mono);color:#A9A59C}
.v-btn{flex:none;min-width:48px;min-height:48px;padding:0 14px;border:1px solid #4a4843;border-radius:6px;font-size:17px}
@media (hover:hover) and (pointer:fine){.v-btn:hover{background:#2a2926}}
.v-x{font-size:15px;font-weight:500}
.viewer :focus-visible{outline-color:#fff}

/* ---- receipt (from direction 16) ---- */
.rwrap{position:fixed;inset:0;z-index:70;background:#1d2024;display:grid;grid-template-rows:auto minmax(0,1fr);color:#ECE9E2}
.r-bar{display:flex;align-items:center;gap:8px;padding:max(10px,env(safe-area-inset-top)) max(14px,env(safe-area-inset-right)) 10px max(14px,env(safe-area-inset-left));border-bottom:1px solid #34373c}
.r-bar p{margin-right:auto;font-size:15px}
.r-bar .btn{color:#ECE9E2;background:none;border-color:#6b6e73}
.r-bar .btn.primary{background:#ECE9E2;color:var(--ink);border-color:#ECE9E2}
.r-scroll{overflow:auto;overscroll-behavior:contain;padding:24px 12px max(40px,env(safe-area-inset-bottom))}
.receipt{--rp:#f6f4ef;--ri:#1b1a1f;width:min(100%,410px);margin:0 auto;font:400 15px/1.5 var(--rmono);color:var(--ri)}
.edge{display:block;width:100%;height:12px;fill:var(--rp)}
.edge.bottom{transform:scaleY(-1)}
.paper{container-type:inline-size;background:var(--rp);padding:14px 16px 24px;box-shadow:0 26px 40px -18px rgb(0 0 0 / .6)}
.paper p,.paper h2,.paper h3{font-size:1em;font-weight:inherit}
.rc{text-align:center}
.b{font-weight:700}
.store{font-weight:700 !important;font-size:min(1.9em,9cqi) !important;line-height:1.2;margin:.2em 0 .4em}
.rule{overflow:hidden;white-space:nowrap;line-height:1;margin:.8em 0;user-select:none}
.rule::before{content:"------------------------------------------------------------------------------------------------"}
.rule.dbl::before{content:"================================================================================================"}
.kv{display:flex;justify-content:space-between;gap:1ch}
.kv span:last-child{text-align:right}
.rrow{display:flex;align-items:baseline;text-decoration:none}
.rrow>:first-child{flex:none;max-width:calc(100% - 7ch)}
.rrow .dots{flex:1 1 1ch;min-width:1ch;overflow:hidden;white-space:nowrap;margin:0 .5ch}
.rrow .dots::before{content:"..................................................................................................."}
.rrow>:last-child{flex:none;text-align:right}
a.rrow{min-height:40px;align-items:center}
a.rrow>:last-child{text-decoration:underline}
.cols{display:flex;font-weight:700}
.cols span:first-child{width:3ch}
.cols span:nth-child(2){flex:1}
.rsec{background:var(--k);color:var(--rp);text-align:center;font-weight:700 !important;letter-spacing:.06em;padding:.2em 0;margin:1.3em 0 .7em;-webkit-print-color-adjust:exact;print-color-adjust:exact}
.rsec.rev{background:var(--ri)}
.rsec.plain{background:none;color:var(--ri)}
.ritem{margin-bottom:1em}
.ritem>.rrow{font-weight:700}
.no{display:inline-block;width:3ch}
.det{padding-left:3ch}
.kv2{display:grid;grid-template-columns:7ch 1fr}
.dith{display:block;width:100%;height:auto;margin:.5em 0 .2em;image-rendering:pixelated;image-rendering:crisp-edges;outline:2px solid var(--ri)}
/* receipt-edges: the picture frame is drawn inside the text column instead of 2px outside it, and the ==== and ---- rules
   end on a whole character instead of a clipped one. */
.dith{outline-offset:-2px}
.rule{width:round(down,100%,1ch)}
.sub{font-weight:700;margin-bottom:.4em}
.total{display:flex;justify-content:space-between;font-weight:700 !important;font-size:2em !important;line-height:1.25}
.prints{display:grid;grid-template-columns:1fr 1fr;gap:1em 10px;margin-top:1em}
.prints .wide{grid-column:1/-1}
.prints figure{margin:0}
.prints img{display:block;width:100%;height:auto;image-rendering:pixelated;image-rendering:crisp-edges}
.prints .tall img{aspect-ratio:2/3;object-fit:cover}
.prints figcaption{text-align:center;font-size:.85em;margin-top:.2em}
.barcode{display:block;text-decoration:none;margin-top:1.4em}
.barcode svg{display:block;width:100%;height:70px;fill:var(--ri)}
.barcode span{display:block;text-align:center;letter-spacing:.18em;margin-top:.3em}

/* ---- case page: a spec sheet, one per project (#case=<id>) ---- */
.case{--k:var(--ink);max-width:1320px;margin:0 auto;padding:env(safe-area-inset-top) max(clamp(16px,3vw,40px),env(safe-area-inset-right)) 40px max(clamp(16px,3vw,40px),env(safe-area-inset-left));font:400 12px/1.55 var(--mono);font-stretch:87.5%;color:var(--ink2)}
body.on-case #detail{display:none}
a.ib{display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:var(--ink);font-family:var(--sans);white-space:nowrap}
.c-bar{display:flex;align-items:center;gap:8px;padding:12px 0;border-bottom:1px solid var(--line)}
.c-pos{margin:0 auto 0 8px;color:var(--ink3);letter-spacing:.08em}
.c-head{padding:20px 0 14px;border-bottom:2px solid var(--ink)}
.c-kind{display:flex;align-items:center;gap:8px;color:var(--k);font-weight:500;text-transform:uppercase;letter-spacing:.06em;font-size:11px}
.c-kind .stt{color:var(--ink2)}
.case h1{font:800 clamp(36px,4vw,54px)/1 var(--sans);letter-spacing:-.04em;color:var(--ink);margin:8px 0}
.case h1:focus{outline:none}
.c-blurb{font:400 17px/1.45 var(--sans);color:var(--ink2);max-width:62ch}
.c-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);gap:0 44px}
.sr{display:flex;align-items:baseline;padding:7px 0;border-bottom:1px solid var(--rule)}
.sr dt{flex:none;text-transform:uppercase;letter-spacing:.08em;color:var(--ink3);font-size:11px}
.sr .dots{flex:1 1 2ch;min-width:2ch;margin:0 1ch;overflow:hidden;white-space:nowrap;color:var(--wire)}
.sr .dots::before{content:"........................................................................................................................"}
.sr dd{flex:0 1 auto;min-width:0;text-align:right;color:var(--ink);overflow-wrap:anywhere}
.sr dd a{text-decoration-color:var(--line)}
@media (hover:hover) and (pointer:fine){.sr dd a:hover{text-decoration-color:var(--ink)}}
.case h2{display:flex;justify-content:space-between;font:500 11px/1 var(--mono);font-stretch:87.5%;text-transform:uppercase;letter-spacing:.08em;color:var(--ink3);margin:18px 0 8px;padding-bottom:7px;border-bottom:1px solid var(--ink3)}
.c-txt{font:400 16px/1.55 var(--sans);color:var(--ink2);max-width:64ch}
.todo{display:inline-block;padding:1px 7px;border:1px dashed var(--ink3);border-radius:3px;background:var(--surface);font:500 11px/1.6 var(--mono);font-stretch:87.5%;color:var(--ink);text-align:left}
.c-ph{display:grid;grid-template-columns:repeat(var(--c),minmax(0,1fr));gap:6px}
.cm{display:flex;width:100%;aspect-ratio:16/10;border:1px solid var(--line);border-radius:3px;overflow:hidden;background:var(--rule)}
.cm img{display:block;width:100%;height:100%;object-fit:cover;object-position:top}
/* case-fill: the pictures get the wider column and at most three across (two up to eight pictures, two on a phone),
   so each thumbnail is large enough to read and the page fills a wide screen. */
@media (min-width:761px){.c-grid{grid-template-columns:minmax(0,5fr) minmax(0,8fr)}}
.c-media .c-none{max-height:none}
@media (max-width:760px){.c-ph:not([style*="--c:1"]){grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (hover:hover) and (pointer:fine){.cm:hover{border-color:var(--ink)}}
.cm.vid{flex-direction:column;justify-content:center;align-items:center;gap:2px;background:var(--ink);color:var(--surface);border-color:var(--ink);font:500 11px/1.3 var(--mono);text-transform:uppercase;letter-spacing:.08em}
.cm.vid small{font-size:11px;text-transform:none;letter-spacing:0;color:#C9C5BB}
.c-none{aspect-ratio:16/10;max-height:300px;border:1px solid var(--rule);border-radius:3px;overflow:hidden;margin-bottom:10px}
.clink{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 4px;font:500 11px/1 var(--mono);font-stretch:87.5%;text-transform:uppercase;letter-spacing:.06em;color:var(--ink3);text-decoration:none;white-space:nowrap}
@media (hover:hover) and (pointer:fine){.clink:hover{color:var(--ink);text-decoration:underline}}
.rlink{text-decoration:underline dotted 1px;text-underline-offset:3px}
@media print{.rlink{text-decoration:none}}
@media (hover:hover) and (pointer:fine){.rlink:hover{text-decoration:underline}}
.clb{touch-action:pinch-zoom;position:fixed;inset:0;width:100%;height:100%;max-width:none;max-height:none;border:0;padding:0;background:#121211;color:#ECE9E2}
.clb[open]{display:grid;grid-template-rows:minmax(0,1fr) auto}
.clb::backdrop{background:#121211}
.clb-m{min-height:0;display:flex;align-items:center;justify-content:center;padding:max(12px,env(safe-area-inset-top)) 12px 0}
.clb-m img{width:100%;height:100%;object-fit:contain}
.clb-m iframe{width:min(100%,calc((100dvh - 110px) * 16 / 9));aspect-ratio:16/9;border:0}
.clb :focus-visible{outline-color:#fff}

/* touch has no hover, so every control shows its hover look while a finger (or the mouse button) is down */
.seg button:not([aria-pressed="true"]):active,.ib:not(:disabled):not([aria-pressed="true"]):active,.views a:not([aria-current="page"]):active,.act:active,.zoom button:active,.ag:active,.pnotes button:active,.card:active{background:var(--rule)}
.v-btn:active{background:#2a2926}
.fchip:active{border-color:var(--ink3)}
.chip:active,.cm:active{border-color:var(--ink)}
.pgrid button:active img{opacity:.88}
.l-contact a:active .contact-link,.lnk:active,.sr dd a:active{text-decoration-color:var(--ink)}

/* ============ phone ============ */
@media (max-width:760px),(max-height:500px) and (max-width:960px){
  :root{--top:52px;--bar2:0px;--tabs:calc(60px + env(safe-area-inset-bottom))}
  #app{grid-template-rows:calc(var(--top) + env(safe-area-inset-top)) auto minmax(0,1fr) var(--tabs)}
  .top{padding-top:env(safe-area-inset-top);gap:4px}
  .brand{margin-right:auto}
  .views{position:fixed;left:0;right:0;bottom:0;z-index:25;margin:0;display:grid;grid-template-columns:repeat(5,1fr);gap:0;border:0;border-top:1px solid var(--line);border-radius:0;padding:4px max(6px,env(safe-area-inset-right)) env(safe-area-inset-bottom) max(6px,env(safe-area-inset-left));background:var(--paper);height:var(--tabs)}
  .views a{flex-direction:column;justify-content:center;gap:3px;min-height:52px;padding:0;font-size:12px;border-radius:8px}
  .views svg{width:22px;height:22px}
  .views a[aria-current="page"]{background:none;color:var(--ink)}
  .views a[aria-current="page"] svg{background:var(--ink);color:var(--surface);border-radius:6px;padding:2px;width:30px;height:24px}
  .views a:not([aria-current="page"]){color:var(--ink3)}
  #searchBtn{display:flex}
  #searchBtn .lbl{display:none}
  .act{padding:0 9px;font-size:15px}
  .bar2{display:none;flex-wrap:wrap;gap:8px;padding:8px 12px}
  body[data-bar] .bar2,body.filtered .bar2{display:flex}
  .search{display:none;width:100%;height:44px}
  .search kbd{display:none}
  body[data-bar="search"] .search{display:flex}
  .filters{display:none;width:100%}
  body[data-bar="filter"] .filters{display:grid;grid-template-columns:1fr 1fr;gap:6px}
  body.filtered:not([data-bar]) .filters{display:flex;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;margin:0 -12px;padding:0 12px;width:calc(100% + 24px)}
  body.filtered:not([data-bar]) .fchip[aria-pressed="false"]{display:none}
  .fchip{min-height:44px;font-size:15px}
  .fclear{min-height:44px}
  .count{margin-left:0;order:3;width:100%}
  body.filtered:not([data-bar]) .count{display:none}
  body[data-view="photos"] body.filtered .bar2{display:none}
  .vhead{padding:12px 14px}
  .mt{font-size:24px}
  .hud{bottom:12px;left:12px;right:12px;transform:none;justify-content:space-between}
  .seg button{min-height:40px;font-size:15px}
  .zoom button{min-width:44px;min-height:40px}
  .mini{display:none}
  .lg{padding:0 14px}
  .pgrid{columns:2;column-gap:6px;padding:0 6px}
  .pgrid li{margin-bottom:6px}
  .photos .vhead .seg{max-width:100%;overflow-x:auto}
  .photos .vhead .seg button{padding:0 10px;font-size:14px}
  .detail{inset:0;top:0;width:auto;border-left:0;box-shadow:none;z-index:40;padding-bottom:env(safe-area-inset-bottom)}
  .d-bar{padding:calc(8px + env(safe-area-inset-top)) 12px 8px}
  .d-body{padding:16px 18px 48px}
  .detail h2{font-size:28px}
  .receipt{font-size:14.5px}
  .c-grid{grid-template-columns:minmax(0,1fr)}
  .c-bar{flex-wrap:wrap}
  .c-nm{display:none}
  .c-pos{order:-1;flex-basis:100%;margin:0 0 4px}
  .c-blurb{font-size:17px}
  .r-bar p{display:none}
  /* calendar-activity-left: on a phone the Project activity block starts at the left margin like the month above it, instead of floating in the middle. */
  .heat{margin:20px 12px 22px}
  .heat-key{justify-content:flex-start}
  .heat-grid{grid-template-columns:repeat(9,8px);grid-template-rows:repeat(7,8px);gap:2px}
}
@media (min-width:761px) and (max-width:1100px) and (min-height:501px),(min-width:961px) and (max-width:1100px){
  .search{width:200px}
}
@media (min-width:761px) and (min-height:501px),(min-width:961px){
  body.has-detail .stage-wrap{margin-right:0}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition:none !important;animation:none !important;scroll-behavior:auto !important}
}

/* ============ print: only the receipt, at receipt width ============ */
@media print{
  @page{margin:5mm}
  html,body{background:#fff !important;height:auto;overflow:visible !important}
  body>*:not(#rwrap){display:none !important}
  #rwrap{display:block !important;position:static;background:none;color:#000}
  .r-bar,.edge{display:none !important}
  .r-scroll{overflow:visible;padding:0}
  .receipt{width:72mm;margin:0;font-size:10pt}
  .paper{box-shadow:none;padding:0;background:none}
  .ritem,.prints figure,.barcode{break-inside:avoid}
}

/* design-tells variant: square corners. Controls and cards go to 2px, the same edge as the receipt
   and spec sheet; true circles (status dots, count badge, today) keep their shape. */
.btn,.seg,.ib,.views,.act,.search,.fchip,.node,.tech,.zoom,.mini,.sortsel select,.v-btn,.chip,.ag,.d-media,.d-videos iframe{border-radius:2px}
.seg button,.views a,.zoom button,.pnotes button,.tth,.c-th,.d-th button,.cm,.c-none,.todo,.search kbd{border-radius:1px}
.frame{border-radius:0}
.nh{border-radius:1px 1px 0 0}
.dn.today{border-radius:2px}
@media (max-width:760px),(max-height:500px) and (max-width:960px){.views a{border-radius:2px}.views a[aria-current="page"] svg{border-radius:2px}}

/* design-tells variant: no pastel fills. Group colour stays on the swatches, frame borders, labels and
   calendar bars; the canvas cards, frames and placeholder covers sit on paper instead of a 13% tint. */
.frame{background:none}
.nh{background:var(--surface);border-bottom-color:var(--line)}
.world.deep .node{background:var(--surface);border-color:color-mix(in srgb,var(--k) 55%,var(--line))}
.cover{background:var(--rule)}

/* design-tells variant: words only in the desktop header. The line icons repeat the labels next to them;
   the phone tab bar keeps its icons because there the label is 12px and the icon is the target. */
@media (min-width:761px) and (min-height:501px),(min-width:961px){.views a svg,.act:not(#searchBtn) svg{display:none}.views a,.act{gap:0}}

/* group jump bar on the canvas */
.gnav{position:absolute;top:10px;left:0;right:0;z-index:5;display:flex;justify-content:center;gap:6px;padding:0 12px;overflow-x:auto;scrollbar-width:none;pointer-events:none}
.gnav button{pointer-events:auto;flex:none;display:flex;align-items:center;gap:8px;min-height:34px;padding:0 12px;background:var(--surface);border:1px solid var(--line);border-radius:2px;font-size:14px;font-weight:600;color:var(--k);white-space:nowrap}
.gnav button b{font:400 12px/1 var(--mono);color:var(--ink3)}
.gnav button[aria-current="true"]{border-color:var(--k);box-shadow:inset 0 -3px 0 var(--k)}
.gnav button:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
@media (max-width:760px),(max-height:500px) and (max-width:960px){.gnav{justify-content:flex-start}.gnav button{min-height:44px}}
