/* =================================================================
   tarín OS — Platinum-flavoured desktop shell
   Static demo. Chrome only; content lives in js/content.js
   ================================================================= */

:root{
  --face:#e8e5dd;
  --face-hi:#ffffff;
  --face-sh:#a9a59b;
  --face-sh2:#6e6b63;
  --ink:#1b1b1b;
  --ink-soft:#5d5a52;
  --sel:#3a5f7d;
  --accent:#ea005f;
  --desk-a:#5c6b6f;
  --desk-b:#39474c;
  --menubar-h:22px;
  --mono:"SF Mono",ui-monospace,"JetBrains Mono",Menlo,Consolas,monospace;
  --ui:"Lucida Grande","Geneva","Helvetica Neue",Helvetica,Arial,sans-serif;
}

*{box-sizing:border-box;}
html,body{height:100%;margin:0;}
body{
  font-family:var(--ui);
  font-size:12px;
  color:var(--ink);
  /* Chrome is furniture, not text. Documents opt back in below. */
  user-select:none;-webkit-user-select:none;
  -webkit-tap-highlight-color:transparent;
  /* Kenzo, dithered to four tones and tiled — a desktop pattern, not a photo.
     Vignette on top keeps the corners readable behind icon labels. */
  background-color:var(--wall-base,#322251);
  background-image:
    radial-gradient(125% 115% at 50% 18%,rgba(255,255,255,.05),rgba(0,0,0,.32) 78%),
    repeating-linear-gradient(0deg,rgba(255,255,255,.018) 0 1px,transparent 1px 3px),
    var(--wall,url("../assets/desktop/kenzo-grape.png"));
  background-size:cover,auto,128px 128px;
  background-repeat:no-repeat,repeat,repeat;
  overflow:hidden;
  -webkit-font-smoothing:antialiased;
}
img{-webkit-user-drag:none;user-select:none;}

/* Set by an inline script in <head>; the shell removes it once it knows
   whether sign-in comes first. Without it a slow stylesheet or a slow
   script can let the bare desktop paint for a frame. */
html.booting #menubar,
html.booting #desktop{visibility:hidden !important;}

/* ------------------------------ seed -----------------------------
   The plain-HTML copy of the page, written by build/prerender.js.

   It is never hidden text. `booting` is set by an inline script in
   <head>, so the moment there is JavaScript this block stops painting,
   and desktop.js deletes it a few milliseconds later. Without
   JavaScript that class is never set, nothing deletes anything, and
   this is simply the page — which is also what a crawler that doesn't
   run scripts reads straight out of the HTML.

   It carries no <img>. The images are declared in JSON-LD and OG tags
   instead, so a real visitor never pays for a gallery they can't see —
   the whole loading model of this site depends on nothing arriving
   until someone asks for it.
   ---------------------------------------------------------------- */
html.booting #seed{display:none !important;}
#seed{
  position:relative;z-index:1;
  max-width:660px;margin:0 auto;padding:48px 24px 80px;
  background:#f2f1ee;color:#16150f;
  font:400 17px/1.7 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
  user-select:text;-webkit-user-select:text;
}
#seed h1{font-size:30px;line-height:1.2;margin:0 0 6px;}
#seed .sub{font-size:19px;color:#55524a;margin:0 0 28px;}
#seed h2{font-size:13px;letter-spacing:.09em;text-transform:uppercase;
  color:#55524a;margin:40px 0 12px;font-weight:600;}
#seed p{margin:0 0 18px;}
#seed a{color:#ea005f;}
#seed ul{margin:0 0 18px;padding-left:20px;}
#seed li{margin-bottom:7px;}
#seed dl{display:grid;grid-template-columns:auto 1fr;gap:5px 18px;margin:0 0 28px;
  font-size:15px;}
#seed dt{color:#55524a;}
#seed dd{margin:0;}

/* ------------------------------ boot ----------------------------
   The Mac OS 9 startup screen: a Platinum dialog over the desktop
   pattern, and extensions marching in along the bottom left.
   ---------------------------------------------------------------- */
#boot{
  position:fixed;inset:0;z-index:9000;
  display:flex;align-items:center;justify-content:center;
  transition:opacity .3s ease;
}
#boot.gone{opacity:0;pointer-events:none;}

.b-dialog{
  width:376px;padding:14px 14px 18px;
  background:#d6d3cb;
  border:1px solid #000;
  box-shadow:
    1px 1px 0 rgba(255,255,255,.9) inset,
    -1px -1px 0 rgba(0,0,0,.22) inset,
    0 6px 18px rgba(0,0,0,.4);
}
.b-panel{
  background:#fff;border:1px solid #7e7a72;
  padding:24px 20px 20px;text-align:center;
  box-shadow:1px 1px 0 rgba(0,0,0,.14) inset;
}
.b-mark{
  width:72px;height:63px;margin:0 auto 14px;
  background:#7f8ad6;color:#12163a;
  display:flex;align-items:center;justify-content:center;
}
.b-mark svg{transform:scale(1.5) translateY(1px);}
.b-word{
  font-family:"Palatino","Book Antiqua","Times New Roman",serif;
  font-size:36px;line-height:1;letter-spacing:.005em;color:#111;
}
.b-status{text-align:center;font-size:11.5px;color:#1b1b1b;margin:13px 0 7px;}
.b-bar{
  height:14px;margin:0 44px;background:#efeee9;
  border:1px solid #6f6b63;
  box-shadow:1px 1px 0 rgba(0,0,0,.16) inset;
  overflow:hidden;
}
.b-bar i{
  display:block;height:100%;width:0;
  background:linear-gradient(#7d86d8,#4a54ad);
  border-right:1px solid #33398a;
  animation:fill 1.5s linear forwards;
}
@keyframes fill{to{width:100%;}}

/* the extension parade */
.b-ext{
  position:absolute;left:10px;bottom:10px;
  display:flex;align-items:flex-end;gap:4px;
}
.b-ext span{
  width:30px;height:30px;display:flex;align-items:center;justify-content:center;
  background:#e8e5dd;border:1px solid #55524b;
  box-shadow:1px 1px 0 rgba(255,255,255,.8) inset,0 1px 2px rgba(0,0,0,.35);
  color:#2b3038;
  animation:extin .18s ease-out backwards;
}
@keyframes extin{
  0%{opacity:0;transform:translateY(5px) scale(.86);}
  100%{opacity:1;transform:none;}
}

/* ------------------------------ login ---------------------------
   Mac OS 9 multi-user sign-in, with a name field instead of a list.
   Log In doubles as the gesture that unlocks audio.
   ---------------------------------------------------------------- */
#login{
  position:fixed;inset:0;z-index:8800;display:none;
  align-items:center;justify-content:center;
  transition:opacity .28s ease;
}
#login.on{display:flex;}
#login.gone{opacity:0;pointer-events:none;}

.lg-dialog{
  width:312px;padding:22px 22px 20px;text-align:center;
  background:#d6d3cb;border:1px solid #000;
  box-shadow:
    1px 1px 0 rgba(255,255,255,.9) inset,
    -1px -1px 0 rgba(0,0,0,.22) inset,
    0 8px 26px rgba(0,0,0,.45);
}
.lg-mark{display:flex;justify-content:center;color:#1a1c3a;margin-bottom:10px;}
.lg-hello{
  font-family:"Palatino","Book Antiqua","Times New Roman",serif;
  font-size:21px;color:#2a2a2a;line-height:1.1;
}
/* The white panel that used to hold the name field is gone with it. The
   dialog is shorter and narrower now, which is what a Platinum dialog
   with two buttons and no input should have been all along. */
.lg-host{
  font-family:"Palatino","Book Antiqua","Times New Roman",serif;
  font-size:31px;color:#111;line-height:1.15;margin-bottom:24px;
}

.lg-btns{display:flex;justify-content:center;gap:34px;}
.lg-btns button{
  display:flex;flex-direction:column;align-items:center;gap:5px;
  background:transparent;border:0;font-family:var(--ui);font-size:11.5px;
  color:var(--ink);cursor:pointer;padding:2px 6px;
}
.lg-btns .ic{
  width:38px;height:38px;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(#fbfaf7,#d9d6cd);
  border:1px solid #7e7a72;border-radius:3px;
  box-shadow:1px 1px 0 rgba(255,255,255,.8) inset,0 1px 2px rgba(0,0,0,.28);
  color:#2b3038;
}
.lg-btns button.default .ic{box-shadow:0 0 0 2px #6d6960,1px 1px 0 rgba(255,255,255,.8) inset;}
.lg-btns button:active .ic{background:#bfbbb2;box-shadow:0 1px 3px rgba(0,0,0,.4) inset;}

/* ---------------------------- console --------------------------- */
#console{
  position:fixed;inset:0;z-index:9600;display:none;
  background:#070907;color:#3f6;
  font-family:var(--mono);font-size:13.5px;line-height:1.65;
  padding:30px 26px;overflow:auto;cursor:text;
  text-shadow:0 0 6px rgba(51,255,102,.35);
}
#console.on{display:block;}
#console::after{
  content:"";position:fixed;inset:0;pointer-events:none;
  background:repeating-linear-gradient(0deg,rgba(0,0,0,.22) 0 1px,transparent 1px 3px);
}
#console .out{white-space:pre-wrap;user-select:text;-webkit-user-select:text;}
#console .dimline{color:#2a7a44;}
#console .cur{
  display:inline-block;width:8px;height:14px;background:#3f6;
  vertical-align:-2px;margin-left:1px;animation:blink 1.05s steps(1) infinite;
}
@keyframes blink{50%{opacity:0;}}

/* ---------------------------- menubar --------------------------- */
#menubar{
  position:fixed;top:0;left:0;right:0;height:var(--menubar-h);z-index:800;
  background:linear-gradient(#fdfdfc,#dcd9d0);
  border-bottom:1px solid #9e9a91;
  display:flex;align-items:center;padding:0 8px;gap:2px;
  box-shadow:0 1px 0 rgba(255,255,255,.6) inset;
  user-select:none;
}
/* the "at" ligature, inheriting menu-bar colour so it inverts when open */
#menubar .mono-mark{
  display:flex;align-items:center;padding:2px 9px;
  border-radius:2px;cursor:default;color:#1a1c3a;
}
#menubar .mono-mark:hover,#menubar .mono-mark.open{background:var(--sel);color:#fff;}
#menubar .mi{padding:2px 9px;border-radius:2px;cursor:default;font-size:12px;}
#menubar .mi:hover,#menubar .mi.open{background:var(--sel);color:#fff;}
#menubar .right{margin-left:auto;display:flex;align-items:center;gap:11px;padding-right:4px;}
#menubar .appname{
  font-size:11.5px;font-weight:600;color:#3b3831;cursor:default;
  padding:1px 8px;border-left:1px solid #c2beb5;
}
#menubar .clock{font-variant-numeric:tabular-nums;font-size:11.5px;cursor:default;}

/* --------------------------- dropdowns -------------------------- */
.dd{
  position:fixed;z-index:9500;min-width:190px;padding:3px 0;
  background:#f6f4ef;border:1px solid #7e7a72;border-radius:0 0 4px 4px;
  box-shadow:0 7px 20px rgba(0,0,0,.35);
}
.dd .item{padding:4px 18px 4px 22px;font-size:12px;cursor:default;white-space:nowrap;position:relative;}
.dd .item:hover{background:var(--sel);color:#fff;}
.dd .item.dim{color:#a9a59b;}
.dd .item.dim:hover{background:transparent;color:#a9a59b;}
.dd .item .tick{position:absolute;left:8px;}
.dd .sep{height:1px;background:#cfcbc2;margin:3px 0;}
/* context menus pop at the pointer, so they get corners all round */
.dd.ctx{border-radius:4px;min-width:158px;}

/* inline rename field */
.rename{
  font:inherit;font-size:11px;text-align:center;width:80px;padding:1px 3px;
  border:1px solid var(--sel);border-radius:2px;background:#fff;color:var(--ink);
  outline:none;user-select:text;-webkit-user-select:text;
}
.flist .rename{text-align:left;width:170px;font-size:12px;}

/* ---------------------------- desktop --------------------------- */
#desktop{position:fixed;top:var(--menubar-h);left:0;right:0;bottom:0;overflow:hidden;}

.dicon{
  position:absolute;width:86px;padding:5px 3px;border-radius:3px;
  display:flex;flex-direction:column;align-items:center;gap:5px;
  cursor:default;user-select:none;text-align:center;
}
.dicon .glyph{filter:drop-shadow(1px 2px 2px rgba(0,0,0,.5));}
/* An icon that's a picture rather than a drawing: the square artwork
   behind a Platinum bezel, the same raised-ring-over-inset-well the
   portrait in Bio.at uses. Built here rather than baked into the file
   because the handheld wants the same square with a different crop, and
   one image with two treatments beats two images. */
.dicon .glyph .appicon{
  display:block;border-radius:50%;padding:2px;
  background:linear-gradient(145deg,#fbfaf7 0%,#e2ded5 45%,#bdb9b0 100%);
  box-shadow:
    0 1px 0 rgba(255,255,255,.85) inset,
    -1px -1px 0 rgba(0,0,0,.18) inset;
}
.dicon .glyph .ai-well{
  display:block;width:100%;height:100%;border-radius:50%;padding:1px;
  background:linear-gradient(145deg,#9a968c 0%,#c6c2b9 50%,#fdfcfa 100%);
}
.dicon .glyph .appicon img{
  width:100%;height:100%;display:block;border-radius:50%;
  object-fit:cover;background:#16223a;
}
/* A cut-out needs none of the above: no ring, no well, no circular clip. */
.dicon .glyph img.appicon.free{
  display:block;border-radius:0;background:none;box-shadow:none;padding:0;
}
.dicon .lbl{
  font-size:11px;line-height:1.25;color:#fff;padding:1px 4px;border-radius:2px;
  text-shadow:0 1px 2px rgba(0,0,0,.85);max-width:84px;
}
.dicon.sel .lbl{background:var(--sel);text-shadow:none;box-shadow:0 0 0 1px rgba(255,255,255,.35);}
.dicon.sel .glyph{filter:drop-shadow(1px 2px 2px rgba(0,0,0,.5)) brightness(1.12);}

/* the disk riding out of the drive, and being drawn back in */
.dicon.ejecting{animation:eject .34s ease-in forwards;pointer-events:none;}
@keyframes eject{
  0%{transform:translateY(0);opacity:1;}
  35%{transform:translateY(7px);opacity:1;}
  100%{transform:translateY(26px) scale(.94);opacity:0;}
}
/* the menu bar dropping in during the startup sequence */
#menubar.dropin{animation:mbdrop .34s cubic-bezier(.2,.9,.3,1.05) backwards;}
@keyframes mbdrop{
  0%{transform:translateY(-100%);opacity:0;}
  100%{transform:translateY(0);opacity:1;}
}

.dicon.mounting{animation:mountin .42s cubic-bezier(.2,.9,.3,1.2) backwards;}
@keyframes mountin{
  0%{transform:translateY(22px) scale(.94);opacity:0;}
  100%{transform:translateY(0) scale(1);opacity:1;}
}

/* Finder zoom rects. White + difference blend reproduces the XOR outline
   the original drew straight onto the screen. */
.zoomrect{
  position:absolute;pointer-events:none;z-index:9999;
  border:1px solid #fff;border-radius:4px;
  mix-blend-mode:difference;
}

/* ---------------------------- windows --------------------------- */
.win{
  position:absolute;display:flex;flex-direction:column;overflow:hidden;
  min-width:280px;min-height:130px;
  background:var(--face);
  border:1px solid #55524b;border-radius:5px 5px 3px 3px;
  box-shadow:0 1px 0 rgba(255,255,255,.75) inset,0 16px 40px rgba(0,0,0,.42),0 3px 9px rgba(0,0,0,.3);
}
.win.shaded > *:not(.titlebar){display:none !important;}
.win.shaded{min-height:0;height:auto !important;box-shadow:0 10px 22px rgba(0,0,0,.35);}

.titlebar{
  flex:0 0 auto;height:22px;display:flex;align-items:center;gap:6px;padding:0 6px;cursor:move;
  background:linear-gradient(#fbfaf7,#d6d3ca);border-bottom:1px solid #a9a59b;
  box-shadow:0 1px 0 rgba(255,255,255,.8) inset;
}
.win:not(.focused) .titlebar{background:linear-gradient(#f1efe9,#e6e3db);}
.win:not(.focused){box-shadow:0 9px 22px rgba(0,0,0,.3);}
.win:not(.focused) .ttl{color:#95918a;}
.win:not(.focused) .wbox{opacity:.4;}

.wbox{
  width:12px;height:12px;flex:0 0 auto;border:1px solid #6d6960;border-radius:2px;
  background:linear-gradient(#fcfbf8,#cbc7bd);
  box-shadow:0 1px 0 rgba(255,255,255,.7) inset;cursor:default;
  display:flex;align-items:center;justify-content:center;
}
.wbox:hover{background:linear-gradient(#fff,#b9b5ab);}
.wbox:active{background:#a8a49a;}
.wbox i{width:6px;height:1.5px;background:#5c584f;display:block;}
.wbox.shade i{height:5px;width:6px;border:1px solid #5c584f;background:none;border-width:1.5px 0 0 0;}
.wbox.zoom i{width:6px;height:6px;border:1.5px solid #5c584f;background:none;}

.pinstripe{flex:1;height:100%;display:flex;align-items:center;gap:0;overflow:hidden;justify-content:center;}
.ttl{
  font-size:12px;font-weight:600;color:#3b3831;white-space:nowrap;padding:0 9px;
  overflow:hidden;text-overflow:ellipsis;max-width:100%;
}
.stripes{flex:1;height:9px;min-width:0;
  background:repeating-linear-gradient(0deg,#a9a59b 0 1px,transparent 1px 2px);opacity:.55;}
.win:not(.focused) .stripes{opacity:0;}

.wbody{flex:1;overflow:auto;background:#fff;position:relative;}
.wbody.plat{background:var(--face);}
.wstatus{
  flex:0 0 auto;height:19px;display:flex;align-items:center;padding:0 9px;gap:10px;
  background:var(--face);border-top:1px solid #bfbbb2;
  font-size:10.5px;color:var(--ink-soft);
}
.grip{position:absolute;right:0;bottom:0;width:15px;height:15px;cursor:nwse-resize;z-index:6;}
.grip::after{
  content:"";position:absolute;right:2px;bottom:2px;width:9px;height:9px;
  background:linear-gradient(135deg,transparent 42%,#a9a59b 42% 56%,transparent 56% 70%,#a9a59b 70% 84%,transparent 84%);
}
.wbody::-webkit-scrollbar{width:13px;height:13px;}
.wbody::-webkit-scrollbar-track{background:#eeebe4;border-left:1px solid #cfcbc2;}
.wbody::-webkit-scrollbar-thumb{background:linear-gradient(90deg,#fdfcfa,#c6c2b8);border:1px solid #a09c93;border-radius:6px;}

/* ------------------------- folder listing ----------------------- */
.flist{width:100%;border-collapse:collapse;font-size:12px;}
.flist thead th{
  position:sticky;top:0;text-align:left;font-weight:400;font-size:10.5px;color:#5d5a52;
  background:linear-gradient(#f5f3ee,#e6e3db);border-bottom:1px solid #bfbbb2;
  padding:3px 10px;border-right:1px solid #d5d1c8;
}
.flist td{padding:4px 10px;border-bottom:1px solid #f0eee9;white-space:nowrap;}
.flist tr{cursor:default;}
.flist tr:hover td{background:#f4f2ed;}
.flist tr.sel td{background:var(--sel);color:#fff;}
.flist tr.sel td .dim{color:#cddbe6;}
.flist .nm{width:100%;display:flex;align-items:center;gap:7px;}
.flist .dim{color:#8d8a82;}

/* ------------------- folder window: chrome & panes ---------------
   A folder window is a fixed toolbar over a pane that splits into the
   listing and, optionally, a preview. Only the inner columns scroll.
   ---------------------------------------------------------------- */
.wbody.fhost{overflow:hidden;display:flex;}
.fview{flex:1;min-width:0;display:flex;flex-direction:column;}
.fpane{flex:1;min-height:0;display:flex;}
.fmain{flex:1;min-width:0;overflow:auto;background:#fff;}
.fmain::-webkit-scrollbar{width:13px;height:13px;}
.fmain::-webkit-scrollbar-track{background:#eeebe4;border-left:1px solid #cfcbc2;}
.fmain::-webkit-scrollbar-thumb{background:linear-gradient(90deg,#fdfcfa,#c6c2b8);border:1px solid #a09c93;border-radius:6px;}

/* toolbar — Platinum bevelled buttons on a brushed strip */
.ftool{
  flex:0 0 auto;display:flex;align-items:center;flex-wrap:wrap;gap:4px;
  padding:5px 8px;background:linear-gradient(#f7f5f1,#e4e1d9);
  border-bottom:1px solid #bfbbb2;user-select:none;
}
.ftool .tlbl{font-size:10.5px;color:#5d5a52;margin-right:1px;}
.ftool .tgrp{display:flex;}
.ftool .tsep{width:1px;height:15px;background:#c6c2b8;margin:0 6px;
  box-shadow:1px 0 0 rgba(255,255,255,.8);}
.tbtn{
  font:inherit;font-size:10.5px;line-height:1;padding:3px 8px;
  border:1px solid #8d8a82;border-radius:3px;background:linear-gradient(#fdfcfa,#ddd9d0);
  box-shadow:0 1px 0 rgba(255,255,255,.8) inset;color:var(--ink);cursor:default;
}
.ftool .tgrp .tbtn+.tbtn{margin-left:-1px;}
.tbtn:hover{background:linear-gradient(#fff,#d2cec5);}
.tbtn:active{background:#c2beb5;box-shadow:0 1px 2px rgba(0,0,0,.22) inset;}
.tbtn.on{
  background:linear-gradient(#bfbbb2,#d8d4cb);color:#1c1a16;
  box-shadow:0 1px 3px rgba(0,0,0,.28) inset;border-color:#7e7a72;
}
.tbtn.off,.tbtn:disabled{
  color:#aaa69d;border-color:#c2beb5;background:linear-gradient(#f6f4f0,#e7e4dc);
  box-shadow:none;text-shadow:0 1px 0 rgba(255,255,255,.9);
}
.tbtn.off:hover,.tbtn:disabled:hover{background:linear-gradient(#f6f4f0,#e7e4dc);}

/* thumbnails view — large icons, the images doing the work */
.fgrid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(126px,1fr));
  gap:6px;padding:12px;align-content:start;
}
.gitem{
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:8px 4px 6px;border-radius:4px;cursor:default;text-align:center;
}
.gitem .gshot{
  width:112px;height:76px;display:flex;align-items:center;justify-content:center;
  border:1px solid #ddd9d1;border-radius:2px;background:#f4f2ed;overflow:hidden;
}
.gitem .gshot img{width:100%;height:100%;object-fit:cover;display:block;}
.gitem .gshot .gph{filter:drop-shadow(0 1px 1px rgba(0,0,0,.18));}
.gitem .glbl{font-size:11px;line-height:1.3;max-width:118px;}
.gitem .glbl .nm{padding:1px 4px;border-radius:2px;display:inline-block;word-break:break-word;}
.gitem:hover .glbl .nm{background:#f0eee9;}
.gitem.sel .glbl .nm{background:var(--sel);color:#fff;}
.gitem.sel .gshot{border-color:var(--sel);box-shadow:0 0 0 1px var(--sel);}

/* divider */
.fsplit{
  flex:0 0 5px;cursor:col-resize;background:linear-gradient(90deg,#cfcbc2,#efece6 40%,#cfcbc2);
  border-left:1px solid #bfbbb2;border-right:1px solid #bfbbb2;
}
.fsplit:hover{background:linear-gradient(90deg,#c2beb5,#e6e3db 40%,#c2beb5);}
body.colresize,body.colresize *{cursor:col-resize !important;}

/* preview pane */
.fprev{
  flex:0 0 auto;width:244px;min-width:160px;display:flex;flex-direction:column;
  background:var(--face);
}
.fpbody{flex:1;min-height:0;overflow:auto;padding:12px 13px 14px;}
.fpbody::-webkit-scrollbar{width:11px;}
.fpbody::-webkit-scrollbar-track{background:#eeebe4;border-left:1px solid #cfcbc2;}
.fpbody::-webkit-scrollbar-thumb{background:linear-gradient(90deg,#fdfcfa,#c6c2b8);border:1px solid #a09c93;border-radius:6px;}
.fpshot{
  width:100%;aspect-ratio:4/3;margin-bottom:10px;overflow:hidden;
  border:1px solid #a9a59b;border-radius:2px;background:#fff;
  box-shadow:0 1px 2px rgba(0,0,0,.16) inset;
}
.fpshot img{width:100%;height:100%;object-fit:cover;display:block;}
.fpshot.glyphonly{display:flex;align-items:center;justify-content:center;background:#f4f2ed;}
.fpname{font-size:12.5px;font-weight:600;line-height:1.3;margin-bottom:2px;}
.fpkind{font-family:var(--mono);font-size:9px;letter-spacing:.08em;text-transform:uppercase;
  color:#8d8a82;margin-bottom:10px;}
.fpcopy,.fpcopy *{user-select:text;-webkit-user-select:text;}
.fpcopy p{font-size:11px;line-height:1.62;margin:0 0 9px;color:#3a382f;}
.fpcopy .fplead{color:var(--ink-soft);font-style:italic;}
.fpcopy .fploading,.fpnone{font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;
  text-transform:uppercase;color:#a09c93;}
.fpfoot{
  flex:0 0 auto;display:flex;align-items:center;gap:9px;padding:7px 12px;
  background:linear-gradient(#f2efe9,#e4e1d9);border-top:1px solid #bfbbb2;
}
.fpfoot .fpcount{font-size:10px;color:var(--ink-soft);line-height:1.25;}

/* --------------------------- document --------------------------- */
/* Real content: selectable and copyable, the way a text viewer should be. */
.doc, .doc *{user-select:text;-webkit-user-select:text;}
.doc{padding:22px 26px 30px;max-width:660px;}
.doc h1{font-size:21px;font-weight:600;margin:0 0 3px;letter-spacing:-.015em;}
.doc .sub{font-size:12.5px;color:var(--ink-soft);margin:0 0 18px;}

/* header with a portrait: photo left, identity right */
.doc .head{display:flex;gap:20px;align-items:flex-start;margin-bottom:20px;}
.doc .head .idcol{flex:1;min-width:0;}
.doc .head .sub{margin-bottom:14px;}
.doc .head .metatbl{margin-bottom:0;}

/* Platinum portrait: raised bezel around an inset well */
.avatar{
  flex:0 0 auto;width:118px;height:118px;border-radius:50%;padding:4px;
  background:linear-gradient(145deg,#fbfaf7 0%,#e2ded5 45%,#bdb9b0 100%);
  box-shadow:
    0 1px 0 rgba(255,255,255,.85) inset,
    -1px -1px 0 rgba(0,0,0,.18) inset,
    0 2px 4px rgba(0,0,0,.28);
}
.avatar .well{
  display:block;width:100%;height:100%;border-radius:50%;padding:2px;
  background:linear-gradient(145deg,#9a968c 0%,#c6c2b9 50%,#fdfcfa 100%);
}
.avatar img{
  width:100%;height:100%;border-radius:50%;display:block;object-fit:cover;
  background:#d8d4cb;
}
.doc .metatbl{width:100%;border-collapse:collapse;margin:0 0 20px;
  border-top:1px solid #ddd9d1;border-bottom:1px solid #ddd9d1;}
.doc .metatbl th{
  text-align:left;font-weight:400;vertical-align:top;white-space:nowrap;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;
  color:#8d8a82;padding:6px 16px 6px 0;width:1px;
}
.doc .metatbl td{padding:6px 0;font-size:12px;vertical-align:top;}
.doc p{font-size:13px;line-height:1.72;margin:0 0 13px;color:#2c2a25;}
.doc .gal{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:9px;margin-top:20px;}
.doc .gal img{width:100%;height:135px;object-fit:cover;display:block;
  border:1px solid #ddd9d1;border-radius:2px;background:#f4f2ed;cursor:pointer;}
.doc .gal img:hover{border-color:var(--accent);}

/* ------------------- documents: two columns -------------------
   A measure has a limit — past ~660px a line of prose gets hard to
   track back to the next one, so the text stops growing. But the
   window doesn't, and the leftover was doing nothing. Widen a
   project past the threshold and the gallery moves up beside the
   copy: read the case and look at the work at the same time.

   The query measures the *window body*, not the viewport, so this
   follows the window as you drag its corner or hit Zoom — two open
   side by side can be in two different layouts at once.
   ---------------------------------------------------------------- */
.wbody.dochost{container-type:inline-size;}
.doc > .txt{min-width:0;}
.doc > .media{min-width:0;}

@container (min-width: 1040px){
  .doc.hasmedia{
    max-width:1358px;margin:0 auto;
    display:flex;align-items:flex-start;gap:38px;
    padding-right:34px;
  }
  /* The measure keeps its cap; only the second column is elastic. */
  .doc.hasmedia > .txt{flex:0 1 660px;}
  /* Capped at 600 because the gallery thumbnails are 520px wide — past
     about 600 they'd be upscaled, and a soft image is a worse trade than
     a little slack. On a very wide window the whole document centres
     instead, rather than one column stretching to fill nothing. */
  .doc.hasmedia > .media{flex:1 1 320px;max-width:600px;}
  /* Already beside the heading — the top margin was there to separate it
     from the paragraph above, and there isn't one any more. */
  .doc.hasmedia > .media > :first-child{margin-top:2px;}

  /* One per row, full width of the column, nothing cropped. Stacked under
     a paragraph the gallery is a contact sheet and a cropped grid is the
     right shape for it; beside the copy there's room to just show the
     work, so each screenshot gets its own line at its own proportions. */
  .doc.hasmedia .gal{display:flex;flex-direction:column;gap:14px;}
  .doc.hasmedia .gal img{
    width:100%;height:auto;aspect-ratio:auto;object-fit:fill;
  }
  .doc.hasmedia video{margin-top:0;margin-bottom:14px;}
}

/* Past this the text should stop taking the extra — a wider gallery is
   worth more than a wider measure it isn't allowed to use. */
@container (min-width: 1500px){
  .doc.hasmedia > .txt{flex:0 0 660px;}
}
.doc video{width:100%;margin-top:20px;border:1px solid #ddd9d1;border-radius:2px;background:#000;}
.doc .lnk{color:var(--accent);text-decoration:none;}
.doc .lnk:hover{text-decoration:underline;}

/* link buttons — Platinum push buttons, not chips */
.doc .linkrow{display:flex;flex-wrap:wrap;gap:7px;margin:0 0 18px;}
.doc .lbtn{
  display:inline-flex;align-items:center;gap:6px;
  font-size:11.5px;line-height:1;padding:5px 12px;border-radius:10px;
  border:1px solid #7e7a72;background:linear-gradient(#fdfcfa,#dcd8cf);
  box-shadow:0 1px 0 rgba(255,255,255,.75) inset;
  color:var(--ink);text-decoration:none;white-space:nowrap;
}
.doc .lbtn:hover{background:linear-gradient(#fff,#d2cec5);border-color:#6d6960;}
.doc .lbtn:active{background:#c2beb5;box-shadow:0 1px 2px rgba(0,0,0,.2) inset;}
.doc .lbtn svg{display:block;flex:0 0 auto;opacity:.75;}
.doc .lbtn:hover svg{opacity:1;}

/* About box: the mark in its magenta, beside the name */
.doc.about{padding:20px 22px 18px;}
.doc.about .abhead{display:flex;align-items:center;gap:16px;margin-bottom:16px;
  border-bottom:1px solid #ddd9d1;padding-bottom:14px;}
.doc.about .abmark{flex:0 0 auto;color:var(--accent);}

/* Kenzo Tower — the canvas letterboxes itself to 3:4, so the box just
   gives it room and a dark surround for the bits it doesn't fill. */
.towerbox{
  height:100%;display:flex;align-items:center;justify-content:center;
  padding:6px;background:#16222f;
}
.towerbox canvas{display:block;border-radius:2px;}

.gamebox{
  height:100%;display:flex;align-items:center;justify-content:center;
  padding:8px;background:var(--face);
}
.gamebox canvas{
  display:block;border:1px solid #7e7a72;
  box-shadow:1px 1px 0 rgba(0,0,0,.18) inset;
  image-rendering:pixelated;
}

/* ------------------------ modal dialogs ------------------------- */
/* z-index is assigned inline from the same counter the windows use, so the
   veil always lands directly beneath its own dialog and above everything else */
.veil{position:absolute;inset:0;background:rgba(20,22,20,.20);}
.win.dlg{border-width:2px;box-shadow:0 18px 46px rgba(0,0,0,.45),0 4px 12px rgba(0,0,0,.35);}
.win.dlg .grip{display:none;}

.dform{padding:15px 16px 16px;}
.dform .lead{font-size:11.5px;color:var(--ink-soft);margin:0 0 13px;}
.dform .field{margin-bottom:10px;}
.dform label{display:block;font-size:11.5px;margin-bottom:3px;}
.dform label .opt{color:#8d8a82;}
.dform input,.dform textarea{
  width:100%;font-family:var(--ui);font-size:12px;padding:4px 6px;color:var(--ink);
  background:#fff;border:1px solid #a9a59b;border-top-color:#7e7a72;border-left-color:#7e7a72;
  border-radius:2px;outline:none;
  user-select:text;-webkit-user-select:text;
}
.dform textarea{height:86px;line-height:1.5;resize:none;}
.dform input:focus,.dform textarea:focus{border-color:var(--sel);box-shadow:0 0 0 1px var(--sel);}
.dform input.bad,.dform textarea.bad{border-color:#a32d2d;box-shadow:0 0 0 1px rgba(163,45,45,.35);}
.dform .err{color:#a32d2d;font-size:10.5px;margin-top:3px;}
.dform .btnrow{display:flex;justify-content:flex-end;align-items:center;gap:9px;
  margin-top:14px;border-top:1px solid #cfcbc2;padding-top:12px;}
/* Platinum default button: the extra ring, not a colour change */
.pbtn.default{box-shadow:0 0 0 2px #6d6960,0 1px 0 rgba(255,255,255,.8) inset;font-weight:600;}
.dform .sent{padding:18px 4px 6px;text-align:center;}
.dform .sent b{display:block;font-size:13px;margin-bottom:6px;}
.dform .sent span{font-size:11.5px;color:var(--ink-soft);}

/* ---------------- Desktop Patterns control panel ---------------- */
.cpanel{padding:13px 14px 14px;}
.cpanel .hint{font-size:11px;color:var(--ink-soft);margin:0 0 11px;}
.wallgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:11px;}
.swatch{cursor:default;}
.swatch .sw{
  height:72px;border:1px solid #8f8b82;border-radius:2px;
  background-repeat:repeat;background-size:56px 56px;
  box-shadow:0 1px 2px rgba(0,0,0,.25) inset;
}
.swatch.on .sw{box-shadow:0 0 0 2px var(--sel);}
.swatch .nm{
  font-size:11px;text-align:center;margin-top:4px;padding:1px 4px;border-radius:2px;
}
.swatch.on .nm{background:var(--sel);color:#fff;}
.cpanel .foot{
  display:flex;align-items:center;gap:9px;margin-top:14px;
  border-top:1px solid #cfcbc2;padding-top:11px;
}
.pbtn{
  font:inherit;font-size:11.5px;padding:3px 13px;border-radius:9px;
  border:1px solid #7e7a72;background:linear-gradient(#fdfcfa,#dcd8cf);
  box-shadow:0 1px 0 rgba(255,255,255,.75) inset;cursor:default;color:var(--ink);
}
.pbtn:hover{background:linear-gradient(#fff,#d2cec5);}
.pbtn:active{background:#c2beb5;}
.cpanel .cur{margin-left:auto;font-size:11px;color:var(--ink-soft);}

/* ------------------------ Kenzo Navigator -----------------------
   Address bar over a frame. The bar is Platinum chrome; everything
   below it belongs to somebody else's website, so it gets a hard
   edge and nothing else.
   ---------------------------------------------------------------- */
.nav{height:100%;display:flex;flex-direction:column;background:var(--face);}
.navbar{
  flex:0 0 auto;display:flex;align-items:center;gap:6px;padding:6px 8px;
  background:linear-gradient(#f7f5f1,#e4e1d9);border-bottom:1px solid #bfbbb2;
}
.navbar .navmark{display:flex;color:#6e6b63;flex:0 0 auto;padding-left:2px;}
.navurl{
  flex:1;min-width:0;font-family:var(--mono);font-size:11px;
  padding:4px 8px;color:var(--ink);background:#fff;
  border:1px solid #a9a59b;border-top-color:#7e7a72;border-left-color:#7e7a72;
  border-radius:2px;outline:none;
  user-select:text;-webkit-user-select:text;
}
.navurl:focus{border-color:var(--sel);box-shadow:0 0 0 1px var(--sel);}
.navurl::placeholder{color:#a9a59b;}
.navbtn{
  flex:0 0 auto;font:inherit;font-size:10.5px;line-height:1;padding:4px 9px;
  border:1px solid #8d8a82;border-radius:3px;background:linear-gradient(#fdfcfa,#ddd9d0);
  box-shadow:0 1px 0 rgba(255,255,255,.8) inset;color:var(--ink);cursor:default;
}
.navbtn:hover{background:linear-gradient(#fff,#d2cec5);}
.navbtn:active{background:#c2beb5;box-shadow:0 1px 2px rgba(0,0,0,.22) inset;}
.navbtn.navout{display:flex;align-items:center;padding:4px 7px;color:#3a3833;}

.navview{flex:1;min-height:0;position:relative;background:#fff;overflow:hidden;}
.navframe{
  position:absolute;inset:0;width:100%;height:100%;
  border:0;display:block;background:#fff;visibility:hidden;
}
.navframe.on{visibility:visible;}
.navmsg{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  padding:26px;background:#fff;overflow:auto;
}
.naverr{max-width:430px;}
.naverr, .naverr *{user-select:text;-webkit-user-select:text;}
.naverr-h{display:flex;align-items:center;gap:10px;margin-bottom:12px;}
.naverr-i{display:flex;color:#a09c93;transform:scale(1.6);transform-origin:left center;margin-right:6px;}
.naverr h2{font-size:15px;font-weight:600;margin:0;letter-spacing:-.01em;}
.naverr p{font-size:12px;line-height:1.7;margin:0 0 11px;color:#3a382f;}
.naverr code{font-family:var(--mono);font-size:10.5px;background:#f0eee9;padding:1px 4px;border-radius:2px;}
.naverr-b{display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin-top:16px;
  border-top:1px solid #ddd9d1;padding-top:15px;}
.naverr-u{font-family:var(--mono);font-size:10px;color:#8d8a82;overflow-wrap:anywhere;}

/* --------------------------- phone:kenzo ------------------------
   The call screen, shared by both machines. Dark, because every
   video call is dark, and because it makes the Navigator's chrome
   read as a window onto something else.
   ---------------------------------------------------------------- */
.callui,.p-call{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:#14161b;overflow:hidden;
}
.p-call{position:relative;flex:1;min-height:0;}
.call-card{display:flex;flex-direction:column;align-items:center;text-align:center;}
.call-card.pulse .call-face{animation:callpulse 1.6s ease-out;}
@keyframes callpulse{
  0%{box-shadow:0 0 0 0 rgba(255,255,255,.42),0 0 0 0 rgba(255,255,255,.24);}
  100%{box-shadow:0 0 0 22px rgba(255,255,255,0),0 0 0 40px rgba(255,255,255,0);}
}
.call-face{
  width:120px;height:120px;border-radius:50%;overflow:hidden;display:block;
  border:2px solid #3a3f49;background:#000;margin-bottom:16px;
}
.call-face img{width:100%;height:100%;display:block;}
.call-name{color:#f2f1ee;font-size:19px;letter-spacing:.01em;margin-bottom:5px;}
.call-state{
  font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:#8b929e;margin-bottom:15px;
}
.call-dots{display:flex;gap:8px;}
.call-dots i{width:7px;height:7px;border-radius:50%;background:#333944;transition:background .18s;}
.call-dots i.on{background:#5ac36a;}

.callvid{
  position:absolute;inset:0;width:100%;height:100%;
  display:block;background:#000;
  /* `contain`, not `cover`: the clips are portrait and the window is wide,
     so cover would crop a phone video down to a leg. Black bars around a
     portrait call on a desktop is what a real call looks like anyway. */
  object-fit:contain;
  /* Shot at 244p on purpose — let it stay soft rather than pretend. */
  image-rendering:auto;
}
.call-badge{
  position:absolute;left:12px;bottom:12px;display:flex;align-items:center;gap:7px;
  padding:5px 11px;border-radius:12px;background:rgba(12,14,18,.72);
  color:#e8e6e1;font-size:10.5px;letter-spacing:.02em;
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
}
.call-badge .dot{width:7px;height:7px;border-radius:50%;background:#5ac36a;flex:0 0 auto;}

/* image viewer */
.iview{background:#1e1e1c;min-height:100%;display:flex;align-items:center;justify-content:center;padding:14px;}
.iview img{max-width:100%;max-height:100%;display:block;}

/* loading states — content arrives only when opened */
.loading{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:#a09c93;padding:26px 2px;
}
.loading.light{color:#7d7a72;}
.wstatus .dim{color:#a09c93;}

/* =========================== iOS 4, 2010 ========================
   The handheld. A different machine from the desktop, with its own
   conventions: a home screen of glossy tiles, a dock, navigation
   bars with a back button, and grouped white cards on a textured
   ground.

   No Apple artwork — their icons are copyrighted. Every gradient,
   gloss and bevel below is ours. The typeface is the system's:
   iOS ran on Helvetica until iOS 7, and Helvetica is already on
   every device this will open on, so there's no font to ship.
   ================================================================ */
#handheld{display:none;}

@media (max-width:900px), (pointer:coarse) and (max-width:1100px){
  html,body{height:100%;overflow:hidden;overscroll-behavior:none;}
  #boot,#menubar,#desktop,#console{display:none !important;}
  /* The desktop wallpaper has no business being visible on the handheld.
     Black here means that if anything ever fails to cover the viewport,
     the seam is invisible instead of a purple stripe. */
  body{background:#000;}

  /* the bezel: screen on top, hardware chin underneath */
  #handheld{
    --bar:clamp(58px, 9dvh, 82px);
    /* One value for both bezels, so they cannot disagree, and never
       smaller than either safe-area inset. Installed to the home screen
       the top inset is ~59px and the bottom ~34px; adding each to its own
       bar is what made them lopsided. Absorbing them into a shared floor
       keeps the black identical top and bottom on every device. */
    --edge:max(var(--bar), env(safe-area-inset-top), env(safe-area-inset-bottom));
    --tint:#4a90d9;
    --sep:#c8c7cc;
    --ink:#000;
    --ink2:#6d6d72;
    display:flex;flex-direction:column;align-items:center;
    /* inset:0 and nothing else. An explicit height on an element already
       pinned to all four edges is over-constrained, and CSS resolves that
       by dropping `bottom` — so when iOS reported a 100dvh shorter than
       the real screen (standalone, viewport-fit:cover) the element came up
       short and the page showed through underneath. Pinned to the edges it
       is exactly the viewport, whatever the units think. */
    position:fixed;inset:0;
    background:#000;color:var(--ink);
    font:17px/1.4 -apple-system,BlinkMacSystemFont,"Helvetica Neue",Helvetica,Arial,sans-serif;
    -webkit-font-smoothing:antialiased;
    -webkit-tap-highlight-color:transparent;
  }
  #handheld *{-webkit-tap-highlight-color:transparent;}

  /* The screen takes everything the bezel doesn't. Letterboxing it to a
     period 3:4 was tried and reverted: it looked right and wasted a third
     of a modern phone, and this is a portfolio before it's a costume. */
  .ios-screen{
    flex:1;min-height:0;width:100%;
    display:flex;flex-direction:column;overflow:hidden;
    background:#e8e8ed;
    box-shadow:0 0 0 1px #26262a;
  }
  /* Brow and chin are the same height so the screen sits centred. The
     chin's floor is the home button plus air; the ceiling stops it eating
     the screen on a tall device. */
  .ios-brow{flex:0 0 var(--edge);}

  /* ------------------------- the chin ------------------------
     Black, because it isn't screen — it's the front of the phone.
     The button is a ring with a rounded square inside it, which is
     what was actually printed on the glass. */
  .ios-chin{
    flex:0 0 var(--edge);background:#000;
    display:flex;align-items:center;justify-content:center;
  }
  .ios-home{
    width:44px;height:44px;border-radius:50%;padding:0;cursor:pointer;
    display:flex;align-items:center;justify-content:center;
    background:radial-gradient(120% 120% at 50% 22%,#1b1b1e,#0a0a0b);
    border:1px solid #303034;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.07), 0 1px 2px rgba(0,0,0,.9);
  }
  .ios-home::after{
    content:"";width:16px;height:16px;border-radius:4.5px;
    border:1.7px solid #5c5c61;
  }
  .ios-home:active{background:radial-gradient(120% 120% at 50% 22%,#2a2a2e,#141416);}
  .ios-home:active::after{border-color:#9a9aa0;}

  /* ----------------------- status bar ----------------------- */
  .ios-sb{
    flex:0 0 auto;position:relative;display:flex;align-items:center;justify-content:space-between;
    height:20px;padding:0 7px;
    background:linear-gradient(#4c4c4c,#1a1a1a);
    color:#fff;font-size:12px;font-weight:700;letter-spacing:.01em;
    text-shadow:0 -1px 0 rgba(0,0,0,.65);
    z-index:5;
  }
  .ios-sb .clock{position:absolute;left:0;right:0;top:0;
    height:20px;line-height:20px;text-align:center;pointer-events:none;}
  .ios-sb .batt{width:23px;height:10px;border:1px solid #fff;border-radius:2px;position:relative;}
  .ios-sb .batt i{position:absolute;inset:1px;width:72%;background:#fff;display:block;}
  .ios-sb .batt::after{content:"";position:absolute;right:-3px;top:2.5px;width:2px;height:5px;background:#fff;}

  /* ------------------------ home screen ---------------------- */
  /* The 2007 home was black. On a 874px phone with six apps that's
     two-thirds of nothing, so this is the 2010 wallpaper instead —
     it gives the grid something to sit on. */
  .ios-screen.home{
    background:
      radial-gradient(125% 85% at 50% 0%,#3d5a78 0%,#16222f 68%),
      #16222f;
  }
  .ios-pages{flex:1;min-height:0;overflow:hidden;}
  .ios-grid{
    display:grid;grid-template-columns:repeat(4,1fr);
    align-content:start;gap:21px 0;padding:22px 10px 0;
  }
  .ios-app{
    display:flex;flex-direction:column;align-items:center;gap:6px;
    text-decoration:none;color:inherit;
  }
  .ios-app:active{opacity:.65;}
  .ios-tile{
    width:57px;height:57px;border-radius:12px;position:relative;overflow:hidden;
    display:flex;align-items:center;justify-content:center;
    box-shadow:0 2px 4px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.22);
  }
  /* the curved shine that defined 2007–2012 */
  .ios-tile::after{
    content:"";position:absolute;left:0;right:0;top:0;height:52%;
    background:linear-gradient(rgba(255,255,255,.6),rgba(255,255,255,.12));
    border-radius:12px 12px 50% 50% / 12px 12px 26% 26%;
  }
  .ios-tile svg{width:30px;height:30px;position:relative;z-index:1;}
  /* Full-bleed artwork, clipped by the tile's own radius — which is what
     an iOS icon is. The plate colour only shows if an image fails, so it
     is white: the set has a light icon in it, and a dark plate flashing
     behind a light icon is worse than the reverse. */
  .ios-tile.art{background:#f2f4f7;}
  /* The cut-out brings no background of its own, so the tile supplies one.
     Dark, not the blue it sits on: against a similar blue the globe loses
     its edge, and dark also puts it in the same family as the two games. */
  .ios-tile.art.plate{background:linear-gradient(#22344f,#0f1a2b);}
  .ios-tile img{width:100%;height:100%;object-fit:cover;position:relative;z-index:1;}
  .ios-lbl{
    font-size:11px;font-weight:500;color:#fff;letter-spacing:.01em;
    text-shadow:0 1px 2px rgba(0,0,0,.85);text-align:center;
  }
  /* app tints — each one its own, the way they were */
  .t-slate{background:linear-gradient(#8fa3c4,#3f5680);}
  .t-blue {background:linear-gradient(#7fc0e8,#2b7fb5);}
  .t-sky  {background:linear-gradient(#9fd0f5,#3d8ec9);}
  .t-grey {background:linear-gradient(#c9c9d2,#6e6e7c);}
  .t-green{background:linear-gradient(#8fd08a,#2f7a3c);}
  .t-wa   {background:linear-gradient(#7ee08a,#1f9d43);}

  /* ------------------------ rotate to portrait ----------------
     A phone on its side has 402px of height, and the home grid needs
     more than that. Rather than reflow the device into a shape it never
     had, ask for the phone back — which is what a phone would do.

     The overlay is a sibling of the screen and swapped by media query
     alone, so it can't fall out of step with whatever view happens to be
     rendered. Bounded by height as well as orientation: a tablet on its
     side has room and gets the real interface. */
  .ios-rotate{display:none;}
  @media (orientation:landscape) and (max-height:560px){
    #handheld > :not(.ios-rotate){display:none;}
    .ios-rotate{
      flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
      gap:20px;padding:24px;text-align:center;background:#000;color:#e8e8ed;
    }
    .ios-rotate .rot-mark{display:block;color:#8f9aa8;}
    .ios-rotate svg{width:66px;height:66px;display:block;overflow:visible;}
    .ios-rotate .rot-phone{
      transform-origin:32px 40.5px;
      animation:rotnudge 3s cubic-bezier(.5,0,.2,1) infinite;
    }
    .ios-rotate p{font-size:16px;line-height:1.45;color:#c8ccd2;letter-spacing:.01em;}
  }
  @keyframes rotnudge{
    0%,42%{transform:rotate(0deg);}
    62%,88%{transform:rotate(-90deg);}
    100%{transform:rotate(0deg);}
  }
  @media (prefers-reduced-motion:reduce){
    .ios-rotate .rot-phone{animation:none;}
  }

  /* A genuinely tiny portrait screen still gets the interface, with the
     bezel down to a sliver and the grid allowed to scroll. */
  @media (orientation:portrait) and (max-height:560px){
    #handheld{--bar:30px;--edge:max(30px, env(safe-area-inset-top), env(safe-area-inset-bottom));}
    .ios-pages{overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;}
    .ios-grid{gap:13px 0;padding:13px 10px 0;}
    .ios-dock{padding:7px 6px 8px;}
    .ios-dots{padding:5px 0 3px;}
  }

  .ios-dots{display:flex;gap:6px;justify-content:center;padding:8px 0 4px;}
  .ios-dots i{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.3);}
  .ios-dots i.on{background:#fff;}
  .ios-dock{
    flex:0 0 auto;display:grid;grid-template-columns:repeat(4,1fr);
    justify-items:center;gap:0;
    margin:0 7px 8px;
    padding:9px 6px 10px;border-radius:14px;
    background:linear-gradient(rgba(255,255,255,.3),rgba(255,255,255,.08));
    border:1px solid rgba(255,255,255,.22);
    -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  }
  .ios-dock .ios-lbl{font-size:10px;}

  /* ------------------------ navigation bar -------------------- */
  .ios-nav{
    flex:0 0 44px;position:relative;display:flex;align-items:center;justify-content:center;
    background:linear-gradient(#aebbcc,#66799a);
    border-bottom:1px solid #3f4d63;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.4);
    z-index:4;
  }
  .ios-title{
    font-size:19px;font-weight:700;color:#fff;
    text-shadow:0 -1px 0 rgba(0,0,0,.5);
    max-width:58%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  /* the pentagon back button, pointed end on the left */
  .ios-back{
    position:absolute;left:7px;top:50%;transform:translateY(-50%);
    font:inherit;font-size:12px;font-weight:700;color:#fff;
    padding:6px 10px 6px 15px;border:0;cursor:pointer;
    background:linear-gradient(#8fa1ba,#546a8c);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.35), 0 1px 0 rgba(0,0,0,.2);
    text-shadow:0 -1px 0 rgba(0,0,0,.45);
    border-radius:4px;
    clip-path:polygon(7px 0,100% 0,100% 100%,7px 100%,0 50%);
    max-width:34%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  .ios-back:active{background:linear-gradient(#6d80a0,#3f5578);}

  /* ------------------------- content area --------------------- */
  .ios-body{
    flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;
    overscroll-behavior:contain;
    padding-bottom:22px;
    /* the pinstriped ground grouped tables sat on */
    background:
      repeating-linear-gradient(45deg,rgba(0,0,0,.02) 0 1px,transparent 1px 3px),
      #e8e8ed;
  }

  /* section header, the small caps bar over a list */
  .ios-hdr{
    padding:5px 12px;font-size:12px;font-weight:700;color:#fff;
    text-shadow:0 1px 1px rgba(0,0,0,.45);
    background:linear-gradient(#a3aab4,#7f8792);
    border-top:1px solid #9aa1ab;border-bottom:1px solid #6d747e;
  }
  .ios-hdr.plain{
    background:none;border:0;color:#4a5464;
    text-shadow:0 1px 0 rgba(255,255,255,.8);
    font-size:13px;padding:18px 15px 6px;
  }

  /* plain table: white rows edge to edge */
  .ios-list{background:#fff;border-bottom:1px solid var(--sep);}
  .ios-row{
    display:flex;align-items:center;gap:10px;
    padding:13px 13px 13px 15px;
    text-decoration:none;color:var(--ink);font-size:17px;
    border-bottom:1px solid var(--sep);
  }
  .ios-row:last-child{border-bottom:0;}
  .ios-row:active{background:linear-gradient(#5aa6e8,#3a7fd0);color:#fff;}
  .ios-row .n{flex:1;min-width:0;}
  .ios-row .y{font-size:15px;color:var(--ink2);}
  .ios-row:active .y{color:rgba(255,255,255,.85);}
  /* the chevron, drawn rather than typed so it sits on the baseline */
  .ios-row .ch,.ios-row .ext{
    flex:0 0 auto;width:11px;height:14px;position:relative;
  }
  .ios-row .ch::after{
    content:"";position:absolute;top:3px;left:0;width:7px;height:7px;
    border-right:2px solid #c3c3c8;border-top:2px solid #c3c3c8;
    transform:rotate(45deg);
  }
  .ios-row:active .ch::after{border-color:rgba(255,255,255,.9);}
  .ios-row .ext::after{
    content:"";position:absolute;top:3px;left:0;width:8px;height:8px;
    border:2px solid #c3c3c8;border-left:0;border-bottom:0;
    transform:rotate(45deg);
  }

  /* ------------------------- documents ------------------------ */
  .ios-doc{padding:15px 15px 4px;}
  .ios-doc,.ios-doc *{user-select:text;-webkit-user-select:text;}
  .ios-doc h1{font-size:26px;font-weight:700;line-height:1.15;margin:2px 0 5px;letter-spacing:-.02em;}
  .ios-doc .sub{font-size:16px;color:var(--ink2);margin:0 0 16px;line-height:1.35;}
  .ios-doc p{font-size:17px;line-height:1.5;margin:0 0 14px;}
  .ios-doc .ios-lede{font-size:15px;color:var(--ink2);margin-bottom:14px;}
  .ios-doc .ios-note{font-size:14px;color:var(--ink2);line-height:1.45;
    margin-top:22px;padding-top:14px;border-top:1px solid var(--sep);}
  .ios-doc .ios-wait{color:var(--ink2);font-size:15px;}
  .ios-doc a,.ios-doc .lnk{color:#3b6ea8;text-decoration:none;}
  .ios-doc .shot{
    width:100%;display:block;margin:0 0 11px;border-radius:6px;
    border:1px solid rgba(0,0,0,.16);background:#000;
  }
  .ios-avatar{
    display:block;width:52%;aspect-ratio:1;margin:0 auto 16px;
    border-radius:50%;overflow:hidden;background:#d8d4cb;
    border:3px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,.28);
  }
  .ios-avatar img{width:100%;height:100%;object-fit:cover;display:block;}

  /* grouped card — the rounded white block on the pinstriped ground */
  .ios-card{
    background:#fff;border-radius:10px;overflow:hidden;margin:0 0 18px;
    border:1px solid rgba(0,0,0,.18);
    box-shadow:0 1px 1px rgba(0,0,0,.06);
  }
  .ios-cell{
    display:flex;flex-wrap:wrap;align-items:baseline;gap:12px;
    padding:11px 13px;border-bottom:1px solid var(--sep);
    font-size:16px;line-height:1.35;
  }
  .ios-cell:last-child{border-bottom:0;}
  .ios-cell > b{flex:0 0 92px;font-weight:600;color:#3b6ea8;font-size:15px;}
  /* basis 0, not auto: with flex-wrap on (so the inline error gets its own
     line) an auto-basis value that doesn't fit jumps to the next line
     instead of wrapping in place, and half the rows end up looking like a
     definition list while the short ones stay inline. */
  .ios-cell > span{flex:1 1 0;min-width:0;overflow-wrap:anywhere;}
  /* the Display card in About — numbers, so they get a numeric face */
  .ios-card.mono .ios-cell{font-family:var(--mono);font-size:12.5px;align-items:flex-start;padding:9px 12px;}
  .ios-card.mono .ios-cell > b{flex:0 0 88px;font-size:12px;font-weight:400;}
  .ios-cell.field{align-items:center;}
  .ios-cell.field input{
    flex:1;min-width:0;font:inherit;font-size:16px;border:0;outline:none;
    background:transparent;color:var(--ink);padding:2px 0;
  }
  .ios-cell.area{padding:9px 11px;}
  .ios-cell.area textarea{
    width:100%;height:120px;font:inherit;font-size:16px;border:0;outline:none;
    background:transparent;resize:none;color:var(--ink);line-height:1.4;
  }
  .ios-cell .err{flex:0 0 100%;font-size:13px;color:#c0392b;padding-top:4px;}
  .ios-cell .bad,.ios-cell input.bad{color:#c0392b;}

  /* glossy pill buttons */
  .ios-btns{display:flex;flex-wrap:wrap;gap:9px;margin:0 0 18px;}
  .ios-btns.wide{flex-direction:column;}
  .ios-btn{
    display:inline-flex;align-items:center;justify-content:center;gap:7px;
    font:inherit;font-size:15px;font-weight:600;color:#2e3d52;
    padding:10px 16px;border-radius:9px;cursor:pointer;text-decoration:none;
    background:linear-gradient(#fdfdfe,#dfe3ea);
    border:1px solid #a6adba;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.9), 0 1px 1px rgba(0,0,0,.12);
  }
  .ios-btns.wide .ios-btn{width:100%;}
  .ios-btn:active{background:linear-gradient(#ccd2dc,#e4e8ee);}
  .ios-btn.primary{
    color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.32);
    background:linear-gradient(#7fb0e8,#2f6fb8);border-color:#2a5f9e;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.45), 0 1px 1px rgba(0,0,0,.18);
  }
  .ios-btn.primary:active{background:linear-gradient(#2f6fb8,#7fb0e8);}
  .ios-btn svg{width:14px;height:14px;flex:0 0 auto;opacity:.8;}

  /* ------------------------ kenzo tower ----------------------- */
  .ios-game.tower .ios-board{flex:1 1 auto;min-height:0;}
  .ios-game.tower .ios-board canvas{
    max-width:100%;max-height:100%;
    /* Snake's board is a pixel grid and wants `pixelated`; this one is
       gradients and needs the opposite. */
    image-rendering:auto;
  }
  .ios-pad.tower{
    flex:0 0 auto;display:block;
    padding:0 4px calc(10px + env(safe-area-inset-bottom));
  }
  /* `.ios-pad button` is two selectors and was beating a single class —
     the drop button came out as one of Snake's 64px round pad keys. */
  .ios-pad.tower .ios-drop{
    width:100%;height:auto;border-radius:11px;
    font:inherit;font-size:19px;font-weight:600;color:#fff;
    padding:15px 0;cursor:pointer;
    text-shadow:0 -1px 0 rgba(0,0,0,.32);
    background:linear-gradient(#7fb0e8,#2f6fb8);border:1px solid #2a5f9e;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.45), 0 1px 2px rgba(0,0,0,.2);
  }
  .ios-pad.tower .ios-drop:active{background:linear-gradient(#2f6fb8,#7fb0e8);}

  /* --------------------------- snake -------------------------- */
  .ios-game{display:flex;flex-direction:column;height:100%;gap:10px;padding:12px 12px 0;}
  .ios-board{flex:1 1 50%;min-height:0;display:flex;align-items:center;justify-content:center;}
  .ios-board canvas{
    display:block;border-radius:8px;image-rendering:pixelated;
    border:1px solid #2a3648;box-shadow:0 2px 8px rgba(0,0,0,.3);
  }
  .ios-score{
    flex:0 0 auto;text-align:center;font-size:14px;font-weight:600;color:var(--ink2);
  }
  .ios-pad{
    flex:1 1 50%;min-height:0;
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
    padding-bottom:6px;
  }
  .ios-pad .row{display:flex;gap:66px;}
  .ios-pad button{
    width:64px;height:64px;border-radius:50%;padding:0;cursor:pointer;
    display:flex;align-items:center;justify-content:center;color:#41506a;
    background:linear-gradient(#fdfdfe,#dbe0e8);
    border:1px solid #a6adba;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.9), 0 1px 2px rgba(0,0,0,.16);
  }
  .ios-pad button svg{width:22px;height:22px;}
  .ios-pad button:active{background:linear-gradient(#7fb0e8,#2f6fb8);color:#fff;border-color:#2a5f9e;}

  /* --------------------------- the call ----------------------- */
  .ios-call{
    position:relative;flex:1;min-height:0;
    height:100%;min-height:240px;
    margin:0;display:flex;align-items:center;justify-content:center;
    background:#14161b;overflow:hidden;
  }
  .ios-call .call-face{width:118px;height:118px;margin-bottom:16px;}
  .ios-call .call-name{font-size:21px;}
  .ios-call .call-state{font-size:11px;}
  .ios-call .call-badge{font-size:12px;}
}
