:root {
  --bg:#FAF9F5; --bg-2:#F0EEE6; --card:#FFFFFF;
  --ink:#1F1E1B; --ink-2:#57544E; --muted:#6F6A62;
  --hairline:rgba(31,30,27,.10); --hairline-strong:rgba(31,30,27,.20);
  --link:#1F1E1B; --focus:#1F1E1B;
  /* Form fields and scrollbars. Ink at low alpha rather than new colours: they stay inside the
     hueless budget (D11) and move with the polarity for free. */
  --field-hover:rgba(31,30,27,.38); --ring:rgba(31,30,27,.14);
  --scroll:rgba(31,30,27,.24); --scroll-hover:rgba(31,30,27,.42);
  /* A person's colour in an AIsle room (D24), the second hue exception after D19. Each tone clears
     3:1 against page, card and bg-2 in its own polarity; yellow is darkened to gold on light because
     pure yellow measures 1.07:1 there. */
  --hue1:#2563EB; --hue2:#DC2626; --hue3:#B7791F; --hue4:#15803D; --hue5:#EA580C; --hue6:#9333EA;
  /* Without this the browser draws every native control — scrollbars, the number spinner, a
     select's dropdown, autofill — as if the page were light, whatever the page actually is. That
     was the white email box and the 2005 scrollbars on the dark theme. */
  color-scheme:light;
  --font-display:Georgia,"Times New Roman",serif;
  --font-body:"Segoe UI",system-ui,sans-serif;
  --font-mono:"Cascadia Mono",ui-monospace,Consolas,monospace;
  --measure:56.25rem; --container:75rem; --radius:8px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg:#141311; --bg-2:#1D1B18; --card:#1A1815;
    --ink:#FAF9F5; --ink-2:#C9C4BB; --muted:#A39E95;
    --hairline:rgba(250,249,245,.10); --hairline-strong:rgba(250,249,245,.20);
    --link:#FAF9F5; --focus:#FAF9F5;
    --field-hover:rgba(250,249,245,.36); --ring:rgba(250,249,245,.16);
    --scroll:rgba(250,249,245,.22); --scroll-hover:rgba(250,249,245,.40);
    --hue1:#60A5FA; --hue2:#F87171; --hue3:#FACC15; --hue4:#4ADE80; --hue5:#FB923C; --hue6:#C084FC;
    color-scheme:dark;
  }
}
* { margin:0; padding:0; box-sizing:border-box; }
body { background:var(--bg); color:var(--ink); font:400 17px/1.5 var(--font-body); -webkit-font-smoothing:antialiased; }
a { color:var(--link); text-decoration:underline; text-underline-offset:2px; text-decoration-thickness:1px; }
/* Colour no longer marks a link apart, so the underline has to answer the pointer itself. */
a:hover { text-decoration-thickness:2px; }
a:focus-visible, button:focus-visible { outline:2px solid var(--focus); outline-offset:2px; }
/* overflow-wrap because an API signature or a URL in <code> has no break opportunity of its own, and
   one of them in a tool note pushed the whole Background Remover page sideways on a phone. */
code { font-family:var(--font-mono); font-size:.92em; background:var(--bg-2); padding:.08em .35em; border-radius:4px; overflow-wrap:anywhere; }

/* ---- Form fields: one look, on every page ------------------------------------------------------
   In CORE, not the tool stylesheet. It used to live in tool.css, and /aisle/ loads only styles.css,
   so the app's fields got no styling at all and fell back to the browser's white box.
   :where() gives these zero specificity on purpose: they are the floor every field stands on, and
   any page-specific rule (.textin, .controls select) still wins without a fight. */
:where(input:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color],[type=button],[type=submit],[type=reset],[type=image]), textarea, select) {
  font:inherit; font-size:.95rem; line-height:1.45; color:var(--ink);
  background-color:var(--card); border:1px solid var(--hairline-strong); border-radius:6px;
  padding:.55rem .75rem; min-height:2.5rem;
  transition:border-color .15s ease, box-shadow .15s ease;
}
:where(input, textarea, select):hover:not(:disabled):not(:focus) { border-color:var(--field-hover); }
/* :focus, not :focus-visible. A text field shows where you are typing whether you arrived by mouse
   or keyboard. The border goes to full ink, which carries the contrast; the soft ring only adds
   presence, so the indicator never depends on a low-alpha colour alone. */
:where(input:not([type=checkbox],[type=radio],[type=range],[type=file]), textarea, select):focus {
  outline:none; border-color:var(--ink); box-shadow:0 0 0 3px var(--ring);
}
:where(input, textarea)::placeholder { color:var(--muted); opacity:1; }
:where(input, textarea, select):disabled { opacity:.5; cursor:not-allowed; }
:where(textarea) { resize:vertical; }
/* A chevron drawn from two gradient triangles in --muted, so it follows the polarity. An SVG data
   URI cannot read a custom property and would be one colour on both themes. background-COLOR in
   the base rule, never the shorthand, or this image is wiped. */
:where(select) {
  appearance:none; -webkit-appearance:none; padding-right:2.1rem; cursor:pointer;
  background-image:linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position:calc(100% - 1.15rem) 50%, calc(100% - .8rem) 50%;
  background-size:.36rem .36rem; background-repeat:no-repeat;
}
/* Chrome paints autofilled fields its own pale yellow or blue, which on the dark theme is a
   glaring slab. An inset shadow is the only paint it lets a page put over that. */
:where(input):-webkit-autofill { -webkit-text-fill-color:var(--ink); caret-color:var(--ink); box-shadow:0 0 0 100px var(--card) inset; }
:where(input):-webkit-autofill:focus { box-shadow:0 0 0 100px var(--card) inset, 0 0 0 3px var(--ring); }
:where(input[type=checkbox], input[type=radio], input[type=range]) { accent-color:var(--ink); }

/* ---- Scrollbars ---------------------------------------------------------------------------------
   A thin pill that sits inside a transparent track, the same on the page and inside every box that
   scrolls. Two mechanisms because the engines split: Firefox has only the standard properties, and
   Chromium and Safari have the pseudo-elements — which Chromium IGNORES the moment scrollbar-color
   is set anywhere. So the standard ones apply only where the pseudo-elements do not exist. */
@supports not selector(::-webkit-scrollbar) {
  html { scrollbar-color:var(--scroll) transparent; scrollbar-width:thin; }
}
::-webkit-scrollbar { width:12px; height:12px; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background:transparent; }
/* The 3px transparent border with content-box clipping is what turns a 12px slab into a 6px pill
   with breathing room — a bigger target to grab than it looks. */
::-webkit-scrollbar-thumb { background-color:var(--scroll); border:3px solid transparent; border-radius:999px; background-clip:content-box; }
::-webkit-scrollbar-thumb:hover { background-color:var(--scroll-hover); }
::-webkit-scrollbar-thumb:active { background-color:var(--ink-2); }

/* The large text area the text tools and the chat use. Moved here from tool.css with the rest of the
   field rules; its focus now comes from the shared rule above rather than a separate hard outline. */
.textin { display:block; width:100%; max-width:var(--measure); margin:1.6rem 0 1.2rem; padding:1rem 1.1rem;
  font:inherit; line-height:1.6; border-radius:var(--radius); }
.wrap { max-width:var(--container); margin:0 auto; padding:0 clamp(1.25rem,4vw,4rem); }
.measure { max-width:var(--measure); }
.vh { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
.skip { position:absolute; left:-9999px; top:0; background:var(--card); color:var(--ink); padding:.6rem 1rem; z-index:10; }
.skip:focus { left:1rem; top:1rem; }

/* padding-BLOCK, never the shorthand. The header is <header class="site wrap">, so both rules land
   on the same element and a padding:1.4rem 0 shorthand here silently wipes the inline inset .wrap
   sets — which is what pushed the mark and the nav out to the window edges, out of line with the
   content below them. Setting only the block axis leaves that inline padding intact, so the
   header's outer edges line up with the page. */
header.site { display:flex; align-items:center; padding-block:1.4rem; }
header.site .mark { width:28px; height:28px; display:block; }
header.site a.home { display:inline-flex; align-items:center; gap:.65rem; font-family:var(--font-display); font-size:1.05rem; color:var(--ink); text-decoration:none; letter-spacing:.02em; }
header.site a.home:hover span { text-decoration:underline; }
header.site nav { margin-left:auto; font-size:.9rem; }
header.site nav [aria-current="page"] { color:var(--muted); text-decoration:none; }

h1 { font-family:var(--font-display); font-weight:400; line-height:1.1; letter-spacing:-.01em; font-size:clamp(2rem,4.5vw,3.4rem); text-wrap:balance; }
h2 { font-family:var(--font-display); font-weight:400; font-size:clamp(1.4rem,2.4vw,2rem); line-height:1.15; margin:2.6rem 0 .9rem; }
h3 { font-size:1.05rem; font-weight:600; margin:1.8rem 0 .5rem; }
p { margin:.85rem 0; color:var(--ink-2); max-width:var(--measure); }
ul { margin:.85rem 0 .85rem 1.2rem; color:var(--ink-2); }
li { margin:.35rem 0; }
strong { color:var(--ink); }

/* The hero wordmark BECOMES the mark. "Abstract Objective" collapses to its two initials, the A and
   the O close on each other, and at the instant they eclipse the mark takes their place — the ring
   IS the O, and the A already lives inside it. The wordmark and the mark share one centred box so
   the swap happens on the spot with no layout shift.
   Pure CSS on purpose: invariant I1 forbids a script on a content page and the build gate enforces
   it, so the whole sequence is keyframes on a shared clock. Timeline:
     0.08s  the name arrives
     1.70s  ONE 1.15s movement: the words collapse and the initials eclipse, on one curve
     2.78s  the letters hand over to the mark   3.55s  the tagline */
.hero { padding:clamp(4rem,16vh,10rem) 0 clamp(3rem,10vh,6rem); text-align:center; display:flex; flex-direction:column; align-items:center;
  --hero-fs:clamp(2.1rem,7.6vw,6.8rem);
  --mark-size:clamp(64px,9vw,104px);
  /* The size the mark must be BORN at so its ring lands on the O it replaces. Measured: Georgia's
     cap O carries 0.680-0.693em of ink depending on size, and the mark's ring spans 98.5% of its
     box, so 0.686 / 0.985 = 0.697em. Being font-derived it tracks the wordmark at every viewport,
     which is what lets the handoff be seamless without a single breakpoint. */
  --mark-seed:calc(var(--hero-fs) * .697); }
/* A DEFINITE square, not a shrink-to-fit box. The lockup is a flex item, so left to itself it would
   size to the wordmark and shrink as the words collapse — and the mark, absolutely positioned and
   wider than that shrinking box, would stop being centred by margin:auto and jam against its left
   edge. Fixing the box to the mark's own size keeps one true centre for the whole sequence; the
   full name is simply allowed to overflow it left and right until it collapses inside. */
.hero .lockup { position:relative; display:flex; align-items:center; justify-content:center;
  width:var(--mark-size); height:max(var(--mark-size), calc(var(--hero-fs) * 1.25)); }
/* The mark is born at the O's exact size and grows into place, so nothing snaps at the swap.
   Its SIZE is animated rather than a transform: a scale factor would have to know the ratio between
   a font-relative seed and a viewport-relative final size, which CSS cannot divide, and every
   workaround is a pile of breakpoints that are wrong between them. */
.hero .mark { position:absolute; inset:0; margin:auto; width:var(--mark-size); height:var(--mark-size);
  opacity:0; animation:resolve .64s cubic-bezier(.2,.7,.25,1) 2.8s forwards; }
.hero h1 { white-space:nowrap; font-size:var(--hero-fs); opacity:0; transform:translateY(12px);
  animation:enter .82s cubic-bezier(.2,.6,.2,1) .08s forwards, dim .32s ease 2.78s forwards; }
/* Georgia sets a cap glyph's ink centre within a rounding error of its box centre, so the default
   origin is already the optical centre — do not "correct" it. */
.hero h1 span { display:inline-block; vertical-align:bottom; }
/* The collapse and the eclipse are ONE movement, so they share ONE clock and ONE curve: same delay,
   same duration, same easing on all three. The letters travel from the full name to eclipsed along
   a single ease, which is the only way the sum of two animations is smooth — overlapping them with
   different curves still jolts, because whichever ends first drops its share of the velocity in one
   frame. Measured at 20ms: the earlier two-curve version peaked at 38px/frame and crashed to 3. */
.hero .rest { overflow:hidden; white-space:pre; animation:collapse 1.15s cubic-bezier(.42,0,.58,1) 1.7s forwards; }
/* Measured widths, not a round ch guess. "bstract " is 3.212em of Georgia and "bjective" 3.328em,
   while the old 8.2ch was 5.03em — so 36% of the collapse was spent shrinking a max-width still
   wider than the text, moving nothing. That dead travel was the hesitation before the words seemed
   to go anywhere. ~15% headroom remains, because overflow:hidden would clip the words outright on a
   face wider than Georgia (DejaVu Serif, where there is no Georgia to fall back from), and a slice
   of dead travel this small is spent inside the ease-in where the curve is near-stationary anyway. */
.hero .r1 { max-width:3.7em; } .hero .r2 { max-width:3.85em; }
.hero .gA { animation:eclipse-a 1.15s cubic-bezier(.42,0,.58,1) 1.7s forwards; }
.hero .gO { animation:eclipse-o 1.15s cubic-bezier(.42,0,.58,1) 1.7s forwards; }
.hero .tag { margin-top:1.6rem; color:var(--muted); font-size:clamp(.95rem,1.6vw,1.1rem); opacity:0; animation:fade .9s ease 3.55s forwards; }
@keyframes enter { to { opacity:1; transform:translateY(0); } }
@keyframes fade { to { opacity:1; } }
@keyframes dim { to { opacity:0; } }
@keyframes collapse { to { max-width:0; opacity:0; } }
@keyframes resolve {
  from { opacity:0; width:var(--mark-seed); height:var(--mark-seed); }
  to   { opacity:1; width:var(--mark-size); height:var(--mark-size); }
}
/* Pure translation. Neither letter is resized: Georgia's cap A already carries WIDER ink than its
   cap O (0.734em against 0.693em), so the two simply sliding together give an A that fills the ring
   and breaks its top — which is the mark. Growing the O was solving a problem that did not exist.
   The two shifts are UNEQUAL and measured. The O's advance is wider than the A's, so the pair's
   centre sits nearer the O and each glyph needs its own distance to reach it. Move both the same and
   the eclipse lands off the mark's centre. Being em-based, these hold at every clamped size. */
@keyframes eclipse-a { to { transform:translateX(.367em); } }
@keyframes eclipse-o { to { transform:translateX(-.330em); } }
@media (prefers-reduced-motion: reduce) {
  /* No transformation to watch, so show the finished lockup: the mark above the full name. */
  .hero .lockup { flex-direction:column; gap:2rem; width:auto; height:auto; }
  .hero .mark { position:static; margin:0; }
  .hero .mark, .hero h1, .hero .rest, .hero .gA, .hero .gO, .hero .tag { animation:none; opacity:1; transform:none; }
}

.band { border-top:1px solid var(--hairline); padding:clamp(3.5rem,9vh,7.5rem) 0; }
.eyebrow { font-family:var(--font-mono); font-size:.72rem; font-weight:500; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); margin-bottom:1.1rem; }
.band h2 { margin:0 0 .9rem; font-size:clamp(1.7rem,3.2vw,2.5rem); line-height:1.15; }
.band p.lead { font-size:1.08rem; margin:.4rem 0 0; }
.band .more { display:inline-block; margin-top:1.7rem; }
.quiet { color:var(--muted); margin-top:1.5rem; font-size:.95rem; }

.cards { display:grid; gap:1rem; margin:2.4rem 0 5rem; }
.cards.cols2 { grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); margin:2.2rem 0 0; }
a.card { display:block; background:var(--card); border:1px solid var(--hairline); border-radius:var(--radius); padding:1.6rem 1.7rem; text-decoration:none; color:var(--ink); transition:border-color .2s; }
a.card:hover { border-color:var(--hairline-strong); }
a.card:hover .ev { text-decoration-thickness:2px; }
a.card .meta { font-family:var(--font-mono); font-size:.72rem; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); }
a.card h2 { margin:.5rem 0 .6rem; font-size:1.45rem; }
a.card p.claim { margin:0; color:var(--ink-2); }
a.card .ev { display:inline-block; margin-top:.9rem; color:var(--link); text-decoration:underline; text-underline-offset:2px; font-size:.85rem; }
.ticon { width:46px; height:46px; color:var(--ink); display:block; }
.card .ticon { width:42px; height:42px; margin-bottom:.75rem; }
/* A shelf with one thing on it: auto-fit would stretch that single card the full 75rem, which reads
   as a banner rather than as one of several. Cap it and it still reads as a card. */
.cards.cols2 > .card:only-child { max-width:38rem; }

/* The AIsle's mark. Its viewBox is 1000x745, so only the width is set and the height follows —
   fixing both would letterbox it inside its own box at every size. */
.aislemark { display:block; width:clamp(88px,12vw,136px); height:auto; color:var(--ink); margin:2.6rem 0 1.6rem; }
article header.entry .aislemark { margin:0 0 1.3rem; }   /* header.entry already pays the top space */
/* The connected accounts, as chips. They are a list of names, not prose, and reading them as prose
   makes five vendors look like a sentence you have to parse. */
.connectors { list-style:none; margin:1.2rem 0 .6rem; padding:0; display:flex; flex-wrap:wrap; gap:.55rem; max-width:var(--measure); }
.connectors li { margin:0; font-family:var(--font-mono); font-size:.8rem; color:var(--ink); background:var(--card); border:1px solid var(--hairline-strong); border-radius:999px; padding:.3rem .85rem; }

/* The AIsle app shell. This is the one page on the site that is not a document — press AIsle and
   you are in a product, not reading about one. It keeps the AO mark on the left so you are never
   lost inside it, and puts its own name beside it: an app inside AO, which is exactly what it is.
   The rest of the site's furniture (band, card, measure) is deliberately absent. */
/* flex-wrap so a narrow bar stacks instead of crushing. Without it the only item that can shrink is
   the one with wrapping text, so "What this is" collapsed to its longest word and grew to three
   lines while everything beside it stayed one — which is what made the bar look misaligned rather
   than merely cramped. */
header.site.appbar { gap:.7rem; row-gap:.5rem; flex-wrap:wrap; border-bottom:1px solid var(--hairline); }
header.site.appbar nav a { white-space:nowrap; }
header.site.appbar .appsep { color:var(--muted); font-size:1.1rem; }
header.site.appbar .appname { display:inline-flex; align-items:center; gap:.5rem; margin:0; font-size:1.05rem; letter-spacing:.02em; }
/* Matched on HEIGHT, not width. The AIsle mark is 1.34x wider than it is tall, so setting both to
   the AO mark's 28px made it 19px high and it read as the smaller of the two. */
header.site.appbar .appname .aislemark { height:28px; width:auto; margin:0; }
/* padding-BLOCK, for the same reason as header.site above: main is <main class="app wrap">, and the
   shorthand zeroed the inline inset .wrap gives it. Invisible on a wide screen, where the container
   is centred with room to spare; below 75rem every panel ran flush to the edge of the glass. */
main.app { padding-block:2rem 4rem; min-height:60svh; }
main.app h2 { font-size:1.2rem; margin:0 0 .5rem; }
/* Scoped to the panels, not to main.app: "main.app p" outweighs ".notopen p" and ".appfoot"
   (element+class+element beats class+element), which quietly squeezed both of those to 46ch. */
.panel p { max-width:46ch; }

/* Said before anything else on the screen, because the screen below it is drawn as if it worked. */
.notopen { display:flex; align-items:baseline; gap:.9rem 1.2rem; flex-wrap:wrap; margin:0 0 2rem; padding:1rem 1.3rem; border:1px solid var(--hairline-strong); border-radius:var(--radius); background:var(--bg-2); }
.notopen p { margin:0; font-size:.95rem; max-width:none; }

/* The messaging-app shape: a rail of lists on the left, the open conversation on the right. The
   rail holds two panels because in this product they are the same question asked twice — which
   room, and who is in it. Below 60rem there is no room for two columns and it stacks. */
.appgrid { display:grid; grid-template-columns:minmax(0,21rem) minmax(0,1fr); gap:1rem; }
/* minmax(0,1fr), here and on every grid below that holds user text. A bare 1fr track is
   minmax(auto,1fr), and auto means "at least as wide as the longest unbreakable thing inside" — so
   one long chat title, or one long command in a message, widened the whole app to 600px and the
   phone scrolled sideways. Zero lets the track be the column and the content wrap, clip or scroll. */
.rail { display:grid; grid-template-columns:minmax(0,1fr); gap:1rem; align-content:start; }
/* One column cannot show the room list and the room at once without burying one of them — the
   conversation ended up below a five-row assistants panel and looked like it had vanished. So the
   narrow layout shows whichever you are in, with a back arrow to the other, which is what every
   messaging app on a phone does. Wide stays side by side and the arrow is not there. */
button.backbtn { display:none; font:inherit; font-size:.85rem; line-height:1.2; color:var(--ink-2); background:none; border:1px solid var(--hairline-strong); border-radius:6px; padding:.32rem .7rem; cursor:pointer; margin-right:.2rem; white-space:nowrap; }
button.backbtn:hover { border-color:var(--ink-2); color:var(--ink); }
@media (max-width:60rem) {
  .appgrid { grid-template-columns:minmax(0,1fr); }
  .appgrid.chatopen .rail { display:none; }
  .appgrid:not(.chatopen) .chatpanel { display:none; }
  .appgrid.chatopen button.backbtn { display:inline-flex; align-items:center; }
  .msglog { max-height:none; }
}
.panel { background:var(--card); border:1px solid var(--hairline); border-radius:var(--radius); padding:1.5rem 1.6rem; }
.panelhead { display:flex; align-items:center; justify-content:space-between; gap:1rem; }
.panelhead h2 { margin:0; }

/* One row list, two jobs: the chats and the assistants. They are the same object — a named thing
   with one control beside it — so they get the same furniture rather than two lookalike rules. */
.rowlist { list-style:none; margin:1.1rem 0 0; padding:0; display:grid; grid-template-columns:minmax(0,1fr); gap:1px; background:var(--hairline); border:1px solid var(--hairline); border-radius:var(--radius); overflow:hidden; }
.rowlist li { margin:0; display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:.7rem 1rem; background:var(--card); }
.rowlist .cname { color:var(--ink); font-weight:500; }
/* One assistant you signed in: what it is, the rooms it reaches, and the way out (M6). A row here
   is two lines rather than one, so the rooms have somewhere to wrap on a phone. */
.rowlist li.assistant { display:block; }
.assistant .arow { display:flex; align-items:center; justify-content:space-between; gap:1rem; }
.assistant .cname { display:inline-flex; align-items:center; gap:.45rem; }
.aroomlist { list-style:none; margin:.5rem 0 0; padding:0; display:flex; flex-wrap:wrap; gap:.4rem; }
.aroomlist li { display:inline-flex; align-items:center; gap:.3rem; margin:0; padding:.15rem .5rem; background:var(--bg-2); border:1px solid var(--hairline); border-radius:999px; font-size:.8rem; color:var(--ink-2); }
button.roomx { font:inherit; font-size:.8rem; color:var(--ink-2); background:none; border:none; padding:0 .15rem; cursor:pointer; }
button.roomx:hover { color:var(--ink); }
select.addroom { font:inherit; font-size:.8rem; color:var(--ink-2); background:var(--bg-2); border:1px solid var(--hairline); border-radius:999px; padding:.15rem .5rem; }
@media (max-width: 560px) { button.roomx, select.addroom { min-height:2.2rem; } }
/* li.rowempty, not .rowempty: ".rowlist li" is class+element and would outweigh a bare class. */
.rowlist li.rowempty { display:block; color:var(--muted); font-size:.9rem; padding:1rem; }
/* Inert on purpose, and visibly so. An app that cannot do anything yet, drawn with buttons that
   look live, is a lie told in CSS — so the disabled state is the designed state, not an oversight. */
/* cursor follows the DISABLED state, not the class. These buttons start disabled and the island
   enables them once you are signed in; a permanent not-allowed cursor on a working button is the
   interface telling you it is broken while it quietly works. */
.rowlist button, button.newchat, button.signin { font:inherit; font-size:.85rem; color:var(--ink-2); background:none; border:1px solid var(--hairline-strong); border-radius:6px; padding:.3rem .85rem; cursor:pointer; white-space:nowrap; }
.rowlist button:hover:enabled, button.newchat:hover:enabled { border-color:var(--ink-2); color:var(--ink); }
button:disabled { cursor:not-allowed; color:var(--muted); }
header.site.appbar nav { display:flex; align-items:center; gap:1rem; }
a.signin { font-size:.85rem; color:var(--ink-2); border:1px solid var(--hairline-strong); border-radius:6px; padding:.32rem .85rem; text-decoration:none; white-space:nowrap; }
a.signin:hover { border-color:var(--ink-2); color:var(--ink); }

/* The account, rightmost, which is where every app puts it and where people look for sign-out.
   A <details> so the menu opens without a line of JavaScript deciding when it should. */
#account { display:flex; align-items:center; }
details.account { position:relative; display:flex; align-items:center; }
details.account summary { list-style:none; cursor:pointer; display:flex; align-items:center; }
details.account summary::-webkit-details-marker { display:none; }
/* 999px rather than 50%: a percentage radius is relative to the box, so anything that makes the box
   non-square — a stray padding, a border-box surprise — quietly turns the circle into a lozenge.
   flex:none so it is never the item that gets squashed when the bar runs out of room. */
.avatar { flex:none; display:grid; place-items:center; width:30px; height:30px; border-radius:999px; background:var(--bg-2); border:1px solid var(--hairline-strong); color:var(--ink); font-size:.85rem; font-weight:600; line-height:1; }
details.account[open] .avatar { border-color:var(--ink-2); }
.accountmenu { position:absolute; right:0; top:calc(100% + .5rem); z-index:20; min-width:15rem; padding:.9rem 1rem; background:var(--card); border:1px solid var(--hairline-strong); border-radius:var(--radius); box-shadow:0 8px 24px rgba(0,0,0,.18); }
.accountmenu p { margin:0; max-width:none; }
.accountwho { color:var(--ink); font-weight:500; }
.accountmail { font-size:.85rem; color:var(--muted); overflow-wrap:anywhere; }
.accountmenu button { margin-top:.8rem; }

/* the conversation */
button.chatrow { display:block; width:100%; text-align:left; font:inherit; color:var(--ink); background:none; border:none; padding:.7rem 1rem; cursor:pointer; }
button.chatrow:hover { background:var(--bg-2); }
button.chatrow.on { background:var(--bg-2); font-weight:500; }
.rowlist li:has(> button.chatrow) { padding:0; display:block; }
/* The conversation column is narrow on purpose. Prose is read in a line of roughly 60 to 70
   characters and this is prose — assistants write paragraphs, not table rows. The panel can be as
   wide as the screen allows; the reading column stays where the eye can track it. */
.msglog { flex:1; margin:1rem 0; padding:1rem 0; border-top:1px dashed var(--hairline-strong); display:grid; grid-template-columns:minmax(0,1fr); gap:1.4rem; align-content:start; overflow-y:auto; max-height:30rem; }
/* The face sits in its own column beside the name, and the message body lines up under the name
   rather than under the face, the way a chat app reads. */
.msg { display:grid; grid-template-columns:24px minmax(0,1fr); column-gap:.65rem; row-gap:.25rem; max-width:calc(64ch + 24px + .65rem); min-width:0; }
.msg > .msgface { grid-row:1 / span 2; align-self:start; }
.msg > .msgwho { align-self:center; }
.msg > .msgbody { grid-column:2; }
.msgface { display:grid; place-items:center; width:24px; height:24px; border-radius:999px; background:var(--bg-2); border:2px solid var(--hairline-strong); color:var(--ink); font-size:.66rem; font-weight:600; line-height:1; box-sizing:border-box; }
/* The assistant's mark keeps the white plate D19 gave it, so its own colour still reads on dark. */
.msgface.agentface { background:#FFFFFF; color:#111111; }
.msgface.agentface svg { width:12px; height:12px; display:block; }
.hue1 { --hue:var(--hue1); } .hue2 { --hue:var(--hue2); } .hue3 { --hue:var(--hue3); }
.hue4 { --hue:var(--hue4); } .hue5 { --hue:var(--hue5); } .hue6 { --hue:var(--hue6); }
.msgface[class*="hue"] { border-color:var(--hue); }
.msg .msgwho { font-family:var(--font-mono); font-size:.7rem; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.msg.agent .msgwho { color:var(--ink-2); }
.msgbody > :first-child { margin-top:0; }
.msgbody > :last-child { margin-bottom:0; }
.msgbody p { margin:.5rem 0; color:var(--ink); overflow-wrap:anywhere; max-width:none; }
.msgbody ul { margin:.5rem 0 .5rem 1.2rem; color:var(--ink); }
.msgbody h2, .msgbody h3 { font-size:1rem; margin:.9rem 0 .3rem; font-family:var(--font-body); font-weight:600; }
/* Code from an assistant is often wide. It scrolls inside its own box rather than widening the room. */
.msgbody pre { margin:.6rem 0; padding:.7rem .85rem; background:var(--bg-2); border:1px solid var(--hairline); border-radius:6px; overflow-x:auto; font-family:var(--font-mono); font-size:.78rem; line-height:1.5; }
.msgbody pre code { background:none; padding:0; font-size:inherit; }
textarea.say { margin:0 0 .6rem; max-width:64ch; }

/* Who is in a room, and what they brought, at a glance. Overlapping circles the way a repository
   host shows contributors, each with its assistant clipped to the corner. */
.faces { display:inline-flex; align-items:center; margin-left:auto; padding-left:.6rem; }
.face { position:relative; width:22px; height:22px; margin-left:-6px; }
.face:first-child { margin-left:0; }
.facein { display:grid; place-items:center; width:22px; height:22px; border-radius:999px; background:var(--bg-2); border:1px solid var(--hairline-strong); box-shadow:0 0 0 2px var(--card); color:var(--ink); font-size:.62rem; font-weight:600; line-height:1; box-sizing:border-box; }
.facein[class*="hue"] { border:2px solid var(--hue); }
/* A FIXED white plate, not a theme token. Brand marks are drawn for light grounds — that is what
   an app icon is — so the badge carries its own plate in both polarities rather than following the
   page. Using --bg-2 here meant the ground went near-black in dark mode, which is what made Claude
   orange muddy and would have made the black Cursor mark invisible outright. The ring stays the
   card colour, so the plate still separates from the circle it is clipped to either way round. */
.agentdot { position:absolute; right:-4px; bottom:-4px; display:grid; place-items:center; width:14px; height:14px; border-radius:999px; background:#FFFFFF; color:#111111; font-size:.5rem; font-weight:700; line-height:1; box-shadow:0 0 0 1.5px var(--card); }
.facemore { margin-left:.35rem; font-size:.7rem; color:var(--muted); }
button.chatrow { display:flex; align-items:center; gap:.5rem; }
/* min-width:0 is what lets the ellipsis happen at all: a flex item will not shrink below its content
   otherwise, and nowrap content is the whole title on one line. */
.chattitle { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* The key, once. The paste-to-your-assistant route comes first because most people have never
   opened a terminal and all of them have an assistant sitting right there. */
/* The copy control sits ON the block, top right, which is where everyone has copied from for years.
   The pre gets right padding so a long line scrolls under the button rather than behind it. */
.codeblock { position:relative; margin:.5rem 0; }
/* Wraps rather than scrolls. The copy button copies from the stored string, never from the DOM, so
   wrapping is purely visual and costs nothing — and it removes the horizontal scrollbar that was
   appearing under every block, plus the second one the page grew underneath it. */
.codeblock pre { margin:0; padding:.8rem 3.2rem .8rem .9rem; background:var(--card); border:1px solid var(--hairline); border-radius:6px; font-family:var(--font-mono); font-size:.76rem; line-height:1.55; color:var(--ink); white-space:pre-wrap; overflow-wrap:anywhere; }
button.copybtn { position:absolute; top:.45rem; right:.45rem; display:grid; place-items:center; width:30px; height:30px; padding:0; color:var(--muted); background:var(--bg-2); border:1px solid var(--hairline-strong); border-radius:6px; cursor:pointer; }
button.copybtn svg { width:15px; height:15px; }
button.copybtn:hover { color:var(--ink); border-color:var(--ink-2); }
button.copybtn.done { color:var(--ink); border-color:var(--ink-2); }

.keyway { margin:1.1rem 0 .2rem; font-family:var(--font-mono); font-size:.7rem; letter-spacing:.08em; text-transform:uppercase; color:var(--ink); }
.keynote { margin:0; font-size:.88rem; color:var(--muted); }
.keybox details { margin-top:.9rem; border-top:1px solid var(--hairline); padding-top:.7rem; }
.keybox summary { cursor:pointer; font-size:.88rem; color:var(--ink-2); }
.agentchip { color:var(--ink-2); }
.agentchip.pending { color:var(--muted); font-style:italic; }
/* A deleted account's messages stay, marked in red at Ofir's request (D30), in the same red the site
   uses for errors. The delete control wears it too, so the one irreversible button looks like one. */
.deletedbadge { margin-left:.45rem; padding:0 .4rem; border:1px solid rgba(192,57,43,.45); border-radius:999px;
  color:#C0392B; font-size:.72rem; line-height:1.5; vertical-align:.1em; white-space:nowrap; }
.dangerlink, .dangerbtn { color:#C0392B; }
.dangerbtn { border-color:rgba(192,57,43,.45); }
@media (prefers-color-scheme: dark) {
  .deletedbadge { color:#E88377; border-color:rgba(232,131,119,.4); }
  .dangerlink, .dangerbtn { color:#E88377; }
  .dangerbtn { border-color:rgba(232,131,119,.4); }
}
.accountdata { margin:.6rem 0 0; font-size:.82rem; color:var(--muted); }
button.linkbtn { font:inherit; font-size:.8rem; color:var(--muted); background:none; border:none; padding:0 0 0 .35rem; cursor:pointer; text-decoration:underline; text-underline-offset:2px; }
button.linkbtn:hover { color:var(--ink); }
/* Marks, at the two sizes that matter. Twelve pixels of shape beats twelve pixels of colour, so
   the badge is monochrome; the picker has room for each mark to be itself. */
/* 9px, not 10. The largest square that fits inside a 14px circle is 14/sqrt(2) = 9.9, and the
   Claude mark is square — at 10px its corners sat exactly on the curve, which is what made a
   perfectly round plate read as an egg. 9px leaves the margin a circle needs and a square does not. */
.agentdot svg { width:9px; height:9px; display:block; }
/* Same reasoning as the badge: a mark gets its own white plate wherever it appears, so a
   monochrome one is never near-white on white and a coloured one never goes muddy on near-black. */
.brandmark { display:grid; place-items:center; width:22px; height:22px; border-radius:6px; background:#FFFFFF; box-shadow:0 0 0 1px var(--hairline-strong); }
.brandmark svg { width:18px; height:18px; display:block; }
/* The initial shown when there is no mark. The plate is fixed white on both themes, so the letter
   has to be fixed dark too — inheriting the page's ink would be white on white in dark mode. */
.brandmark { color:#111111; font-size:.72rem; font-weight:600; line-height:1; }
.clientpick { display:flex; flex-wrap:wrap; gap:.5rem; margin:.9rem 0 .2rem; }
button.clientopt { display:flex; align-items:center; gap:.45rem; font:inherit; font-size:.82rem; color:var(--ink-2); background:var(--card); border:1px solid var(--hairline-strong); border-radius:999px; padding:.3rem .8rem .3rem .45rem; cursor:pointer; }
button.clientopt:hover { border-color:var(--ink-2); color:var(--ink); }
button.clientopt.on { border-color:var(--ink); color:var(--ink); background:var(--bg-2); }
button.ghostbtn { font:inherit; font-size:.85rem; color:var(--ink-2); background:none; border:1px solid var(--hairline-strong); border-radius:6px; padding:.32rem .85rem; cursor:pointer; }
button.ghostbtn:hover { border-color:var(--ink-2); color:var(--ink); }
/* "Connect an assistant" while you have none in this room: the button breathes a soft ink ring,
   hueless like every other control, and stops the moment an assistant is connected. Anyone who asked
   the system for less motion gets a steady ring instead of the pulse. */
button.ghostbtn.nudge { color:var(--ink); border-color:var(--ink-2); animation:nudge 1.6s ease-in-out infinite; }
@keyframes nudge { 0%, 100% { box-shadow:0 0 0 0 var(--field-hover); } 50% { box-shadow:0 0 0 5px var(--field-hover); } }
@media (prefers-reduced-motion: reduce) { button.ghostbtn.nudge { animation:none; box-shadow:0 0 0 3px var(--ring); } }
/* Two in a row ("Get the key", "Cancel") had no space between them at all, which read as one
   split button — and at finger height it made the pair look glued together. */
button.ghostbtn + button.ghostbtn { margin-left:.5rem; }

/* The key, shown once. Deliberately loud, because it cannot be shown again. */
.keybox { margin:0 0 1.4rem; padding:1.1rem 1.2rem; background:var(--bg-2); border:1px solid var(--ink-2); border-radius:var(--radius); }
.keybox h3 { margin:0 0 .3rem; }
.keybox pre { margin:.7rem 0; padding:.8rem .9rem; background:var(--card); border:1px solid var(--hairline); border-radius:6px; font-family:var(--font-mono); font-size:.76rem; line-height:1.5; color:var(--ink); white-space:pre-wrap; overflow-wrap:anywhere; }
.keybox p { max-width:none; }
/* Claude first, with nothing to copy, and a line under it so the key half below reads as the
   fallback it is rather than the main event (M6). It is a link, not a button — it leaves for
   claude.ai — so it borrows the button's shape rather than looking like stray underlined text. */
.connectfirst { margin:0 0 1.1rem; padding-bottom:1rem; border-bottom:1px solid var(--hairline); }
.connectfirst h3 { margin:0 0 .3rem; }
.connectfirst .toolbar { margin:.7rem 0 0; }
a.ghostbtn { display:inline-block; font-size:.85rem; color:var(--ink-2); border:1px solid var(--hairline-strong); border-radius:6px; padding:.32rem .85rem; text-decoration:none; }
a.ghostbtn:hover { border-color:var(--ink-2); color:var(--ink); }
a.ghostbtn.primary { color:var(--bg); background:var(--ink); border-color:var(--ink); }
a.ghostbtn.primary:hover { color:var(--bg); opacity:.88; }
@media (max-width: 560px) { a.ghostbtn { min-height:2.75rem; line-height:2.1rem; } }
/* The address and its button share one line and one height, so the button reads as belonging to
   the field rather than floating under it. Wraps on a narrow screen instead of squeezing the field. */
.inviterow { display:flex; flex-wrap:wrap; gap:.5rem; align-items:stretch; margin:.5rem 0 .2rem; }
.inviterow .textin { flex:1 1 14rem; min-width:0; margin:0; }
.invitebox .keynote:not([hidden]) { margin:.4rem 0 .2rem; color:var(--ink); }
.inviterow :where(input) { flex:1 1 14rem; min-width:0; }

/* ---- A popup ------------------------------------------------------------------------------------
   A native <dialog> opened with showModal(). The browser supplies what a hand-built overlay gets
   wrong: the top layer (nothing on the page can sit above it), focus kept inside while it is open,
   Escape to close, and everything behind it made inert to clicks and screen readers. */
dialog.modal {
  margin:auto; padding:0; width:min(34rem, calc(100vw - 2rem)); max-height:calc(100dvh - 2rem);
  color:var(--ink); background:var(--bg); border:1px solid var(--hairline-strong); border-radius:12px;
  box-shadow:0 28px 70px -18px rgba(0,0,0,.5); overflow:auto; overscroll-behavior:contain;
}
dialog.modal::backdrop { background:rgba(12,11,10,.55); backdrop-filter:blur(3px); }
dialog.modal[open] { animation:modal-in .18s ease-out; }
dialog.modal[open]::backdrop { animation:backdrop-in .18s ease-out; }
@keyframes modal-in { from { opacity:0; transform:translateY(8px) scale(.985); } }
@keyframes backdrop-in { from { opacity:0; } }
@media (prefers-reduced-motion: reduce) { dialog.modal[open], dialog.modal[open]::backdrop { animation:none; } }
.modalhead { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:1.1rem 1rem .3rem 1.4rem; }
.modalhead h3 { margin:0; font-size:1.15rem; }
button.modalx { display:grid; place-items:center; width:34px; height:34px; font:inherit; font-size:1.3rem; line-height:1; color:var(--muted); background:none; border:1px solid transparent; border-radius:8px; cursor:pointer; }
button.modalx:hover { color:var(--ink); border-color:var(--hairline-strong); }
.modalbody { padding:.1rem 1.4rem 1.4rem; }
.modalbody p { max-width:none; }
.modalbody .keyway:first-child { margin-top:.6rem; }
.modalsep { border:0; border-top:1px solid var(--hairline); margin:1.3rem 0 0; }
.rowlist .later { font-family:var(--font-mono); font-size:.7rem; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); }
.freeline { margin-top:1.3rem; font-size:.95rem; }

/* The path from nothing to working, numbered. It is the first thing a signed-out visitor should
   read, so it sits where the open conversation will be rather than under a heading further down. */
.flowlist { margin:.4rem 0 1rem 1.3rem; padding:0; color:var(--ink-2); }
.flowlist li { margin:.5rem 0; padding-left:.2rem; }
.connectors li.on { border-color:var(--ink); color:var(--ink); }

.chatpanel { min-height:22rem; display:flex; flex-direction:column; min-width:0; }
.chatempty { flex:1; display:flex; flex-direction:column; gap:.3rem; padding:1.5rem 0 0; border-top:1px dashed var(--hairline-strong); margin-top:1rem; }
.chatempty p { color:var(--ink-2); }
.chatempty .quiet { margin-top:0; font-size:.9rem; }
.appfoot { margin-top:2.4rem; font-size:.9rem; color:var(--muted); max-width:none; }

/* How an assistant joins. Eight clients, each with a block of syntax, is a wall of code if it is all
   open at once — so each one is a <details>. Native, no script, and the page still works with
   JavaScript off, which invariant I1 requires of everything under /aisle/. */
.joinpanel { margin-top:3rem; padding-top:2rem; border-top:1px solid var(--hairline); }
.joinpanel h2 { margin:0 0 .7rem; font-size:1.3rem; }
/* A URL inside <code> has no break opportunities, so the cell refused to narrow and pushed the
   whole page sideways on a phone. Let it break anywhere, and pin the table to the column so it
   cannot be widened by its contents in the first place. */
.joinpanel table.plain { width:100%; table-layout:fixed; }
.joinpanel table.plain th { width:9rem; }
.joinpanel table.plain code { overflow-wrap:anywhere; }
.joins { display:grid; gap:1px; background:var(--hairline); border:1px solid var(--hairline); border-radius:var(--radius); overflow:hidden; margin-top:1.6rem; max-width:var(--measure); }
.joins details { background:var(--card); }
.joins summary { cursor:pointer; padding:.8rem 1rem; display:flex; align-items:baseline; gap:.7rem; flex-wrap:wrap; }
.joins summary::marker { color:var(--muted); }
.joins .jclient { color:var(--ink); font-weight:500; }
.joins .jeffort { font-family:var(--font-mono); font-size:.72rem; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.joins .jwarn { font-family:var(--font-mono); font-size:.66rem; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-2); border:1px solid var(--hairline-strong); border-radius:999px; padding:.1rem .5rem; }
/* Commands are wide. They scroll inside their own box rather than pushing the page sideways. */
.joins pre { margin:0 1rem .6rem; padding:.9rem 1rem; background:var(--bg-2); border-radius:6px; overflow-x:auto; font-family:var(--font-mono); font-size:.78rem; line-height:1.55; color:var(--ink); }
.joins .jnote { margin:0 1rem 1rem; font-size:.88rem; color:var(--muted); max-width:none; }

/* AIsle — the about page. The status badge is not decoration. It is the page saying out loud, before the
   reader invests any attention, how far from usable the thing actually is. */
.statusbox { display:flex; align-items:baseline; gap:.9rem 1.2rem; flex-wrap:wrap; max-width:var(--measure); margin:0 0 2.2rem; padding:1rem 1.3rem; background:var(--bg-2); border:1px solid var(--hairline); border-radius:var(--radius); }
.statusbox p { margin:0; font-size:.95rem; }
.badge { font-family:var(--font-mono); font-size:.68rem; font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:var(--ink); border:1px solid var(--hairline-strong); border-radius:999px; padding:.24rem .7rem; white-space:nowrap; }
/* "What it is" beside "what it is not", because the second column is only honest while the reader
   can see it without scrolling past the first. min(100%,20rem) so the pair stacks instead of
   overflowing when the viewport is narrower than one column. */
.pair { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,20rem),1fr)); gap:.2rem 2.6rem; max-width:var(--measure); margin:2.2rem 0 1rem; }
.pair h3 { margin-top:1.3rem; }

article header.entry { padding-top:3.5rem; }
article header.entry .ticon { margin-bottom:1rem; }
article .meta { font-family:var(--font-mono); font-size:.75rem; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); margin-bottom:1rem; }
article h1 { margin-bottom:1.4rem; }
article p.lead { font-size:1.08rem; }
.claimbox { font-family:var(--font-display); font-size:1.25rem; line-height:1.5; color:var(--ink); background:var(--bg-2); border-left:3px solid var(--ink); border-radius:0 var(--radius) var(--radius) 0; padding:1.1rem 1.4rem; margin:0 0 2.2rem; max-width:var(--measure); }
section.evidence { margin:3rem 0 4rem; padding:1.6rem 1.7rem; background:var(--card); border:1px solid var(--hairline); border-radius:var(--radius); max-width:var(--measure); }
section.evidence h2 { margin:0 0 1rem; font-size:1.3rem; }
section.evidence .numbers li { color:var(--ink-2); }
section.evidence .sources { margin-top:1.1rem; padding-top:1rem; border-top:1px solid var(--hairline); font-size:.9rem; }

.likebox { display:flex; align-items:center; gap:.9rem; margin:0 0 2.4rem; }
button.like { display:inline-flex; align-items:center; gap:.5rem; font:inherit; font-size:.95rem; color:var(--ink); background:var(--card); border:1px solid var(--hairline-strong); border-radius:var(--radius); padding:.45rem .95rem; cursor:pointer; transition:border-color .2s, background-color .2s; }
button.like:hover { border-color:var(--ink-2); }
.heart { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:1.8; }
button.like.liked .heart { fill:#FF0000; stroke:#FF0000; }
.likenote { font-size:.8rem; color:var(--muted); }
.cardwrap { position:relative; }
.cardwrap .card { height:100%; }
.cardlike { position:absolute; top:.85rem; right:.85rem; z-index:1; display:inline-flex; background:none; border:none; padding:.35rem; cursor:pointer; color:var(--muted); border-radius:6px; }
.cardlike:hover { color:var(--ink); }
.cardlike .heart { width:17px; height:17px; }
.cardlike.liked { color:#FF0000; }
.cardlike.liked .heart { fill:#FF0000; stroke:#FF0000; }

table.plain { border-collapse:collapse; margin:1.2rem 0; font-size:.92rem; max-width:var(--measure); }
table.plain th, table.plain td { text-align:left; padding:.5rem .9rem .5rem 0; border-bottom:1px solid var(--hairline); vertical-align:top; }
table.plain th { font-weight:600; color:var(--ink); }
table.plain td { color:var(--ink-2); }

footer.site { border-top:1px solid var(--hairline); margin-top:4rem; padding:1.6rem 0 2.4rem; font-size:.85rem; color:var(--muted); }
footer.site a { color:var(--muted); }

/* ---- Phones -------------------------------------------------------------------------------------
   Measured before any of this was written: every page at 375px, for sideways scroll, controls under
   24px (the WCAG 2.2 floor) and fields that make iOS zoom. Three layout bugs are fixed where they
   live, above. What is here is the rest, in two kinds, kept apart on purpose:

   WIDTH rules tighten what a narrow screen has no room for.
   POINTER rules size things for a finger. They key on pointer:coarse, not on width, because a
   narrow desktop window still has a mouse and should keep the density it had, and a tablet is wide
   and still has a finger. */

@media (max-width:60rem) {
  /* The open room's head holds a back button, the title and "Connect an assistant". Three in a row
     does not fit, and letting it wrap put the connect button alone on a line under the title. So the
     two buttons share the top row and the title takes the full line beneath them. Scoped by :has, so
     the Chats head, which has no back button, keeps its title and button side by side. */
  .panelhead:has(> .backbtn) { flex-wrap:wrap; row-gap:.7rem; }
  .panelhead:has(> .backbtn) h2 { order:3; flex-basis:100%; overflow-wrap:anywhere; }
}

@media (max-width:40rem) {
  /* Card and panel padding was sized for a desktop, where it is breathing room. At 375px, inside a
     20px gutter, it cost a quarter of the width of every line of text. */
  .panel { padding:1.15rem 1rem; }
  a.card { padding:1.3rem 1.2rem; }
  section.evidence { padding:1.25rem 1.1rem; }
  .notopen, .statusbox { padding:.85rem 1rem; }
  .claimbox { padding:1rem 1.1rem; font-size:1.15rem; }
}

@media (pointer:coarse) {
  /* iOS Safari zooms the page into any field whose text is under 16px the moment it is tapped, and
     does not zoom back out. The shared fields are .95rem and the tool controls smaller still, so every
     tap into a field on an iPhone threw the layout off. !important because the compact tool rules
     are deliberately more specific than the shared field rule, and this one has to beat them all:
     it is a platform constraint, not a style. */
  input:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color]), textarea, select { font-size:16px !important; }

  /* Buttons reach 44px, the size a fingertip needs. Only the height moves; the look does not. */
  button.ghostbtn, button.newchat, button.signin, button.backbtn, button.clientopt { min-height:2.75rem; }
  a.signin { display:inline-flex; align-items:center; min-height:2.75rem; }
  button.modalx { width:2.75rem; height:2.75rem; }

  /* Small things that must stay small to read right — nav words, "cancel" inside a sentence, the heart
     on a card, the copy button on a code block — get an invisible hit area around them instead of a
     bigger box. A pseudo-element adds target without moving a single pixel of layout. */
  header.site a.home, header.site nav a, button.linkbtn { position:relative; }
  header.site a.home::after, header.site nav a::after, button.linkbtn::after, .cardlike::after, button.copybtn::after { content:""; position:absolute; inset:-.6rem -.3rem; }
  /* The nav words are 19px of text; .8rem above and below brings them to 44. */
  header.site nav a:not(.signin)::after { inset:-.8rem -.3rem; }
  header.site a.home::after { inset:-.5rem; }
  .cardlike::after, button.copybtn::after { inset:-.45rem; }
  details.account summary { padding:.45rem; margin:-.45rem; }
  footer.site { line-height:2.2; }
}
/* A keyboard shortcut is noise on a screen that has no keyboard. */
@media (hover:none) and (pointer:coarse) { .kbdhint { display:none; } }

/* The page an assistant's sign-in lands on (D26), rendered by the server with no script at all. One
   calm column: what is asking, where it returns to, which room, and two buttons. */
main.consent { max-width:36rem; padding-block:clamp(2.5rem,8vh,5rem); }
main.consent h1 { font-size:clamp(1.6rem,4vw,2.1rem); margin:0 0 1.2rem; }
main.consent p { max-width:none; }
.consentwarn { border-left:3px solid var(--ink-2); padding:.4rem 0 .4rem .9rem; color:var(--ink); }
fieldset.consentrooms { border:1px solid var(--hairline-strong); border-radius:var(--radius); padding:.6rem 1rem .8rem; margin:1.4rem 0; }
fieldset.consentrooms legend { padding:0 .4rem; font-size:.9rem; color:var(--ink-2); }
label.consentroom { display:flex; gap:.7rem; align-items:baseline; padding:.55rem 0; cursor:pointer; }
label.consentroom + label.consentroom { border-top:1px solid var(--hairline); }
label.consentroom input { accent-color:var(--ink); margin:0; }
.consentactions { display:flex; gap:.6rem; margin-top:1.6rem; }
.consentactions button.ghostbtn { font-size:1rem; padding:.55rem 1.4rem; min-height:2.75rem; }
.consentactions button.ghostbtn + button.ghostbtn { margin-left:0; }
button.ghostbtn.primary { color:var(--bg); background:var(--ink); border-color:var(--ink); }
button.ghostbtn.primary:hover:enabled { color:var(--bg); opacity:.88; }
button.ghostbtn:disabled { opacity:.45; cursor:not-allowed; }
.consentwho { font-size:1.02rem; }
label.consentroom input:disabled + span { opacity:.55; }
/* Allow cannot be clicked for its first second on screen. A page that swaps this one in under a
   double-click (opening it on the first click) would otherwise land the second click on Allow. It is
   not motion, so it stays under reduced motion; afterwards the button is exactly the ordinary one. */
button.ghostbtn.primary.arm:enabled { animation:consent-arm 1s step-end; }
@keyframes consent-arm { from, to { pointer-events:none; opacity:.55; } }
