/* Reset, body shell, and the design tokens (:root) every other sheet uses. */
/* Hide Turbo's top-of-page progress bar. Almost every interaction here is
   a Turbo Stream response (chat, plug toggle, panel actions) that completes
   in well under the 500ms delay before the bar appears, OR is a same-page
   stream swap that doesn't need a navigation cue. The brief flash on slower
   responses reads as "page reloading" — exactly the impression we don't
   want when the company stays mounted. */
.turbo-progress-bar {
  display: none !important;
}

/* Self-hosted Inter from app/assets/fonts — Propshaft serves it digested, no
   build step and no third-party request on first paint. One face carries
   everything, headings included: a second, characterful cut for h1/h2 was
   dropped 2026-08-14, since the brand brief scales headings by size, weight and
   tracking and never named a display face. Subsets are unicode-range gated, so
   an English page fetches latin alone and the Cyrillic cut lands only when the
   content actually contains it — agent-written chat can be any language. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-latin-496a588b.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-latin-ext-5a6754fc.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-cyrillic-a10feb6d.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* The italic cut is not optional decoration: the wordmark is bold italic text
   and chat renders italic prose. Without it the browser slants the upright face
   mechanically, which is exactly what the system font never did. */
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-italic-latin-80cac1ae.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-italic-latin-ext-7db1c008.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-italic-cyrillic-c6e5a17f.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

/* The chrome palette. Light is the only theme (2026-07-27); the dark ladder
   it replaced lives in git history, not in a selector nothing sets. SCREEN
   surfaces (terminal, noVNC display, desk-game canvases) are intentionally
   NOT themed — a monitor reads dark on any page — so their #0b0f19 / #06090f
   / #000 stay literal in the sheets. */
:root {
  /* White page (2026-08-24, was the pale blue #f4f7fb). Cards share the
     surface now, so separation is carried by hairlines and shadow, and
     the panel/deep steps below are the only tinted grounds left. */
  --bg: #ffffff;
  --bg-card: #ffffff;
  --bg-card-hover: #eef2f8;
  --bg-panel: #eef2f7;
  --text: #1e293b;
  --text-muted: #64748b;
  --accent: #0284c7;
  --accent-hover: #0369a1;
  --green: #16a34a;
  --amber: #d97706;
  --red: #dc2626;
  /* THE border of the company chrome; -strong is the emphasized variant.
     Slate ink at low alpha on light (was slate at low alpha on dark). Other
     alphas of the same slate stay literal — one-offs, not the system line. */
  --hairline: rgba(15, 23, 42, 0.1);
  --hairline-strong: rgba(15, 23, 42, 0.16);
  /* Fill ladders for blocks sitting on the page surface. On light these are
     DARK (slate-ink) overlays — the dark theme's white overlays would vanish.
     Neutral: soft = resting, raised = hover/focus/chip. Cool slate/accent:
     soft = whisper fill, chip = badges/pills, active = the selected row.
     Pick a step; don't mint a sixth. */
  --fill-soft: rgba(15, 23, 42, 0.035);
  --fill-raised: rgba(15, 23, 42, 0.06);
  --tint-soft: rgba(15, 23, 42, 0.04);
  --tint-chip: rgba(2, 132, 199, 0.08);
  --tint-active: rgba(2, 132, 199, 0.1);
  /* The warn tint, the amber sibling of the two above: the ground a handback
     mark sits on, so the ⏸ chip is a different OBJECT from a receipt and not
     just the same one in another colour. */
  --tint-warn: rgba(217, 119, 6, 0.1);
  /* Spacing scale — step N is N × 4px. Every new padding, gap and margin picks
     a step. Off-grid one-offs (0.35rem, 0.85rem, 0.95rem, 1.1rem) are most of
     what makes a layout read hand-assembled rather than designed; the existing
     ones migrate when their own rule is next touched, not in a sweep. */
  /* Interface face everywhere; the display face is scoped to public headings
     in 10_marketing.css. Both fall back to the system stack that used to be
     the whole answer, so a font that fails to load costs nothing. */
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --radius: 1rem;
  --radius-sm: 0.5rem;
  --radius-pill: 999px;
  /* Motion scale — three steps, the same way spacing picks a --space-N.
     fast: hover, focus, colour and border. base: things that move or appear.
     slow: context shifts (overlays, drawers). The house curve is the easing
     for anything that should feel expensive; entering decelerates. */
  --dur-fast: 120ms;
  --dur: 220ms;
  --dur-slow: 400ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --topbar-height: 3.5rem;
  /* Company right-rail track width — the live surfaces, over the key
     metric. It was sized when the rail also carried the accounts panel;
     that moved to the left column (2026-08-18) and the chat took the slack. */
  --rail-width: clamp(19em, 24vw, 29em);
  /* The left column: the agent header, the task list, and the spotlight
     panels that undock over them. The floor is what the header's energy row
     needs on ONE line (amount + top-up button beside the avatar gutter) —
     below it the row has to wrap, and the header stops reading as two floors.
     Still narrower than the rail, so the chat keeps the middle. */
  --stage-width: clamp(17em, 19vw, 26em);
  /* The cover art, named once: the landing's fold and the doorway pages
     (sign-in, the invite gate) are the same picture, and `rake hero_image`
     writes a new one under a new name. */
  --cover-art: url("/assets/marketing/hero-cover-drive-day-86ab1813.webp");
}

/* ===== The drawn marks =====
   One set, one geometry, everywhere the interface needs a glyph. They replace
   platform emoji, which drew themselves differently on every machine, brought
   their own colour, and sat at their own optical size next to our type.
   Masked rather than <img>, so the ink is `currentColor` (the mark is as quiet
   as the text it rides with) and the size is in em. Markup, not a ::before, so
   the geometry is written once and every surface points at the same class.

   One drawing system, so a row of them reads as one set (2026-09-15 sweep,
   which found six stroke weights and ink from 10 to 20 units wide):
     - 24-square viewBox, ink inside 4..20 — a circle or a square fills it, a
       cross or a chevron sits a shade inside, which is what makes them look
       the same size rather than measure the same;
     - stroke 1.8, round caps and joins, no fill. The exceptions are written
       where they are taken: `send` (reversed out of a disc), the two solid
       glyphs (`paused`, `caret`) and `energy`, which is the currency mark and
       keeps its own box;
     - radius 2 on a rectangle's corners, and nothing drawn so finely that it
       survives only above 22px — every mark is checked at 16. */
:root {
  --mark-model: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4 19 8v8l-7 4-7-4V8z'/%3E%3C/g%3E%3C/svg%3E");
  --mark-notes: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 6.3A1.8 1.8 0 0 1 8.8 4.5h6.4A1.8 1.8 0 0 1 17 6.3V19.6L12 16.2l-5 3.4z'/%3E%3C/g%3E%3C/svg%3E");
  --mark-clip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 11v4.6a4.2 4.2 0 0 1-8.4 0V7.8a2.8 2.8 0 0 1 5.6 0v7.6a1.4 1.4 0 0 1-2.8 0V8.4'/%3E%3C/g%3E%3C/svg%3E");
  /* Pause bars are drawn CHUNKY and solid: the thin full-height outline pair
     this replaced read as chopsticks at 1rem. Narrower than the outline marks
     around them because a filled shape carries more ink at the same width. */
  --mark-paused: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='6.4' y='5' width='4.2' height='14' rx='1.6'/%3E%3Crect x='13.4' y='5' width='4.2' height='14' rx='1.6'/%3E%3C/svg%3E");
  /* A reply arrow: the one state in a list that names the action wanted of
     the reader. The pause bars this replaced said "stopped", and the ringed
     question mark that followed read as confusion (2026-09-18). */
  --mark-reply: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 5.5 4.5 10.5l5 5'/%3E%3Cpath d='M4.5 10.5H14a5.5 5.5 0 0 1 0 11h-2'/%3E%3C/g%3E%3C/svg%3E");
  --mark-waiting: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4a8 8 0 1 1 0 16 8 8 0 0 1 0-16z'/%3E%3Cpath d='M12 7.4V12l3.2 1.9'/%3E%3C/g%3E%3C/svg%3E");
  --mark-lock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5.6' y='10.4' width='12.8' height='9.4' rx='2'/%3E%3Cpath d='M8 10.4V8a4 4 0 0 1 8 0v2.4'/%3E%3C/g%3E%3C/svg%3E");
  --mark-download: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v10.4M7.8 10.4 12 14.6l4.2-4.2M4.8 19.4h14.4'/%3E%3C/g%3E%3C/svg%3E");
  --mark-gear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg transform='translate(2.4 2.4) scale(.8)' fill='none' stroke='%23000' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 15.2a3.2 3.2 0 1 0 0-6.4 3.2 3.2 0 0 0 0 6.4zM19 12a7 7 0 0 0-.1-1.2l2-1.5-2-3.4-2.3 1a7 7 0 0 0-2-1.2L14.2 3H9.8l-.4 2.7a7 7 0 0 0-2 1.2l-2.3-1-2 3.4 2 1.5A7 7 0 0 0 5 12a7 7 0 0 0 .1 1.2l-2 1.5 2 3.4 2.3-1a7 7 0 0 0 2 1.2l.4 2.7h4.4l.4-2.7a7 7 0 0 0 2-1.2l2.3 1 2-3.4-2-1.5A7 7 0 0 0 19 12z'/%3E%3C/g%3E%3C/svg%3E");
  --mark-card: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='6' width='16' height='12' rx='2'/%3E%3Cpath d='M4 10.2h16M7.4 14.4h3.4'/%3E%3C/g%3E%3C/svg%3E");
  --mark-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' d='M6.6 6.6 17.4 17.4M17.4 6.6 6.6 17.4'/%3E%3C/svg%3E");
  /* Drawn solid, like the pause bars and for the same reason: on the Up next
     floor the triangle is 0.72rem, and at that size a 1.8 outline with round
     joins is more join than triangle. Narrower than the outline marks, and the
     ink is nudged right of centre — a triangle's optical centre is behind its
     tip. */
  --mark-play: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath stroke='%23000' stroke-width='2.2' stroke-linejoin='round' d='M9 7.2 16.6 12 9 16.8z'/%3E%3C/svg%3E");
  --mark-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' d='M12 5.6v12.8M5.6 12h12.8'/%3E%3C/svg%3E");
  --mark-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.2 12.4 9.8 17 18.8 7.4'/%3E%3C/g%3E%3C/svg%3E");
  /* The one stroke off the family's 1.8: this arrow is reversed out of a
     filled accent disc, and a light stroke on a dark ground optically thins
     until it reads as a hairline. */
  --mark-send: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 19.6V5.2M6.4 10.8 12 5.2l5.6 5.6'/%3E%3C/g%3E%3C/svg%3E");
  --mark-reply: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19.6 17.6v-1.4a4.4 4.4 0 0 0-4.4-4.4H4.6M9.2 7.2 4.4 12l4.8 4.8'/%3E%3C/g%3E%3C/svg%3E");
  /* A list of places, for the head that opens them (chats/_head). The set had
     no such glyph: `notes` is a document and `caret` is a disclosure, and
     neither says "the other chats". Same 24-square, same 1.8 stroke as the
     rest, so it sits at cap height with them. */
  /* A box with its lid on: how a chat ends (chats.md rule 3) — put away,
     not finished. */
  /* An arrow, not a chevron: a chevron says "there is more this way", an
     arrow says "you are going there" — and the row it sits on does move you
     (2026-09-17). Not the caret either: that one is a filled triangle and
     means a menu drops. */
  --mark-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' d='M5 12h13M12.2 5.8 18.5 12l-6.3 6.2'/%3E%3C/svg%3E");
  --mark-list: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M9 6.5h10M9 12h10M9 17.5h10'/%3E%3Cpath d='M5 6.5h.01M5 12h.01M5 17.5h.01'/%3E%3C/g%3E%3C/svg%3E");
  --mark-caret: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath stroke='%23000' stroke-width='1.6' stroke-linejoin='round' d='M6.4 9.6h11.2L12 16.4z'/%3E%3C/svg%3E");
  /* The alarm strip's glyph. Drawn as a triangle rather than a circle so it
     reads as a warning at 1em without any colour of its own. */
  --mark-alert: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4.6 20.4 19.4H3.6z'/%3E%3Cpath d='M12 10v4M12 17.2h.01'/%3E%3C/g%3E%3C/svg%3E");
  --mark-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='5.8' width='16' height='12.4' rx='2'/%3E%3Cpath d='m4.6 7 7.4 5.4 7.4-5.4'/%3E%3C/g%3E%3C/svg%3E");
  --mark-compose: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11.4 5H6.6a2 2 0 0 0-2 2v10.4a2 2 0 0 0 2 2H17a2 2 0 0 0 2-2v-4.8'/%3E%3Cpath d='M17.6 4.2 19.8 6.4l-8.4 8.4-3 .8.8-3z'/%3E%3C/g%3E%3C/svg%3E");
  /* A sheet with a dog-ear and two lines of writing on it: the corner alone
     drew a blank page, and what the mark names is a document. Radiused like
     the mail and phone rects — the square-cut version read as a notch at 16px. */
  --mark-page: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 5.2a1.8 1.8 0 0 1 1.8-1.8h5.4L18 8.2v10.6a1.8 1.8 0 0 1-1.8 1.8H7.8A1.8 1.8 0 0 1 6 18.8z'/%3E%3Cpath d='M13.2 3.4v3.2a1.6 1.6 0 0 0 1.6 1.6H18'/%3E%3Cpath d='M9.4 13.4h5.2M9.4 17h3.2'/%3E%3C/g%3E%3C/svg%3E");
  /* Angle brackets around a slash — code, as every editor draws it. Ink kept
     inside 5..19 so it reads at the same weight as the globe beside it. */
  --mark-code: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 8.2 5.2 12 9 15.8M15 8.2 18.8 12 15 15.8M13.4 6.2l-2.8 11.6'/%3E%3C/g%3E%3C/svg%3E");
  --mark-globe: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8'/%3E%3Cpath d='M4 12h16M12 4c-2.8 3.4-2.8 12.6 0 16 2.8-3.4 2.8-12.6 0-16z'/%3E%3C/g%3E%3C/svg%3E");
  --mark-link: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.4 13.6a3.4 3.4 0 0 0 4.8 0l2.4-2.4a3.4 3.4 0 0 0-4.8-4.8l-1.2 1.2'/%3E%3Cpath d='M13.6 10.4a3.4 3.4 0 0 0-4.8 0l-2.4 2.4a3.4 3.4 0 0 0 4.8 4.8l1.2-1.2'/%3E%3C/g%3E%3C/svg%3E");
  /* Thumb, in the row's own ink. One drawing for both: a thumbs-down is a
     thumbs-up turned 180°, which is what the down button does to it. */
  --mark-thumb: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 10v12'/%3E%3Cpath d='M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z'/%3E%3C/g%3E%3C/svg%3E");
  /* The same thumb, pressed: a rating has to read as a state from across the
     row, and a 1.5px outline under the meta strip's muted grey does not. */
  --mark-thumb-fill: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M2 21h4V9H2v12zM23 10a2 2 0 0 0-2-2h-6.31l.95-4.57.03-.32a1.5 1.5 0 0 0-.44-1.06L14.17 1 7.59 7.59A2 2 0 0 0 7 9v10a2 2 0 0 0 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z'/%3E%3C/svg%3E");
  --mark-energy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13.2 19.6'%3E%3Cpath d='M9.4 0 0 11.7h6L3.8 19.6 13.2 7.9H7.2z'/%3E%3C/svg%3E");
  --mark-phone: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7.2' y='4' width='9.6' height='16' rx='2.2'/%3E%3Cpath d='M10.8 16.8h2.4'/%3E%3C/g%3E%3C/svg%3E");
  --mark-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' d='M6.5 12.2l3.8 3.8 7.2-7.6'/%3E%3C/svg%3E");
  --mark-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8'/%3E%3Cpath d='M12 7.4V12l3 1.8'/%3E%3C/g%3E%3C/svg%3E");
  --mark-hourglass: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 4h9M7.5 20h9'/%3E%3Cpath d='M9 4v3.2L12 12l-3 4.8V20'/%3E%3Cpath d='M15 4v3.2L12 12l3 4.8V20'/%3E%3C/g%3E%3C/svg%3E");
  --mark-trash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.5 7h13'/%3E%3Cpath d='M10 7V5.5h4V7'/%3E%3Cpath d='M7.2 7l.7 11.5h8.2L16.8 7'/%3E%3Cpath d='M10.4 10.6v5M13.6 10.6v5'/%3E%3C/g%3E%3C/svg%3E");
  --mark-archive: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 6.5h15v3.5h-15z'/%3E%3Cpath d='M6 10v7.5h12V10'/%3E%3Cpath d='M10 13.2h4'/%3E%3C/g%3E%3C/svg%3E");
  --mark-dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%23000'%3E%3Ccircle cx='12' cy='5.6' r='1.7'/%3E%3Ccircle cx='12' cy='12' r='1.7'/%3E%3Ccircle cx='12' cy='18.4' r='1.7'/%3E%3C/g%3E%3C/svg%3E");
  --energy-ink: var(--amber);
}

.mark,
.energy-mark {
  display: inline-block;
  /* Sized so the INK lands at cap height, not so the boxes match: every
     outline mark is drawn inset in its 24-square (ink ≈ 0.66 of the box), so
     a 1em box drew a glyph noticeably shorter than the letters beside it. */
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.24em;
  /* Own gap, so an inline call site doesn't have to remember one. */
  margin-right: 0.28em;
  background-color: currentColor;
  mask: var(--mark) center / contain no-repeat;
  /* Never squeezed by a flex row it rides in. */
  flex: 0 0 auto;
}

/* …and zeroed wherever the mark is a flex child of a row that already owns a
   gap, or sits alone in a button, where the trailing margin either doubled
   the space or pushed the glyph off centre. */
.chat-attach .mark,
.chat-send .mark,
.chat-message-file > .mark,
.chat-readonly-notice > .mark,
.wallet__balance > .energy-mark,
.wallet__topup > .mark,
.task-panel__state > .mark,
.page-lightbox__close > .mark {
  margin-right: 0;
  /* Whole pixels: at the inherited em size the glyph box came out 15.33px,
     which put a 1.2px stroke on half a pixel and made the ✕ read smudged. */
  width: 1rem;
  height: 1rem;
}

/* The paperclip is alone in a 2.5rem button, borderless, so the glyph itself
   is the affordance — it carries the whole button and is drawn accordingly. */
.chat-attach .mark {
  width: 1.7rem;
  height: 1.7rem;
}

/* Energy is the one mark that keeps a colour of its own: it stands for money,
   and it is the only figure on these surfaces the eye should be able to find
   without reading — as currentColor it read as one more grey number in a grey
   row. Its box is cropped to the bolt, so unlike the others the ink IS the box
   — hence its own pair of numbers for the same drawn height. Narrow, because a
   bolt is a narrow shape, but not so narrow it disappears at the task list's
   0.72rem: the amount beside it is the smallest type on the page. */
.energy-mark {
  --mark: var(--mark-energy);
  background-color: var(--energy-ink);
  width: 0.62em;
  height: 0.92em;
  vertical-align: -0.11em;
}

.mark--model   { --mark: var(--mark-model); }
.mark--notes   { --mark: var(--mark-notes); }
.mark--list    { --mark: var(--mark-list); }
.mark--arrow   { --mark: var(--mark-arrow); }
.mark--clip    { --mark: var(--mark-clip); }
.mark--paused  { --mark: var(--mark-paused); }
.mark--waiting { --mark: var(--mark-waiting); }
.mark--reply   { --mark: var(--mark-reply); }
.mark--lock     { --mark: var(--mark-lock); }
.mark--download { --mark: var(--mark-download); }
.mark--gear     { --mark: var(--mark-gear); }
.mark--card     { --mark: var(--mark-card); }
.mark--play     { --mark: var(--mark-play); }
.mark--plus     { --mark: var(--mark-plus); }
.mark--close    { --mark: var(--mark-close); }
.mark--check    { --mark: var(--mark-check); }
.mark--send     { --mark: var(--mark-send); }
.mark--reply    { --mark: var(--mark-reply); }
.mark--caret    { --mark: var(--mark-caret); }
.mark--alert    { --mark: var(--mark-alert); }
/* The chat chips' receipts: the object the agent touched (Message::CHIPS). */
.mark--mail     { --mark: var(--mark-mail); }
.mark--page     { --mark: var(--mark-page); }
.mark--compose  { --mark: var(--mark-compose); }
.mark--globe    { --mark: var(--mark-globe); }
.mark--code     { --mark: var(--mark-code); }
.mark--link     { --mark: var(--mark-link); }
.mark--thumb    { --mark: var(--mark-thumb); }
/* The bolt as a plain mark: same drawing as .energy-mark, but in the row's own
   ink — a menu label is not a figure to find without reading. */
.mark--energy   { --mark: var(--mark-energy); }
.mark--archive { --mark: var(--mark-archive); }
.mark--trash   { --mark: var(--mark-trash); }
.mark--wait    { --mark: var(--mark-hourglass); }
.mark--clock   { --mark: var(--mark-clock); }
/* The tick that says done: thicker than the chrome's check, drawn to sit in
   the middle of a disc. */
.mark--tick    { --mark: var(--mark-tick); }
.mark--dots    { --mark: var(--mark-dots); }
.mark--phone    { --mark: var(--mark-phone); }

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* The `hidden` attribute wins over a class. The browser's own rule is a bare
   `[hidden] { display: none }`, which ANY class setting `display` outranks —
   so every element some JS hides has to be found out the hard way, one at a
   time, and it was: eight of these had accumulated across five sheets by
   2026-09-16, each a separate rediscovery of the same trap (a grid head that
   would not hide, a flex scroller that stayed under the list it was replaced
   by). One rule instead, so `el.hidden = true` simply works. */
[hidden] { display: none !important; }

body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  /* Flex column + min-height: 100vh + `margin-top: auto` on a footer
     (.marketing-footer) pins it to the bottom of the viewport when the page
     content is short. Layouts that want to fill the viewport themselves
     (company, signin-page) set their own height via calc(100vh - topbar) so
     this change is transparent to them. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Sticky-footer side-effect repair: in a flex-column container, a child
   with `margin: 0 auto + max-width` (the standard "centered page wrapper"
   pattern used by .profile-page, .tasks-page) collapses to
   content-width because auto cross-axis margins
   disable align-items: stretch. Forcing width: 100% restores the expected
   block-element behavior — the child fills cross-axis up to max-width,
   then auto margins center it. Excluded: position-fixed elements like the
   connection-status pill which would expand to viewport width. */
body > *:not(.connection-status-pill):not(.flash-toast) {
  width: 100%;
}

/* ===== Flash toast =====
   The redirect feedback surface (shared/_flash) — alerts and notices land
   here on the next render. Transient: enters on the house curve, holds
   long enough to read, fades itself out; pointer-events off so the ghost
   never blocks the page underneath. */
.flash-toast {
  position: fixed;
  top: 1rem;
  left: 50%;
  z-index: 100;
  max-width: min(34rem, calc(100vw - 2rem));
  padding: 0.55rem 1rem;
  border-radius: var(--radius-pill);
  font-size: 0.85rem;
  font-weight: 500;
  background: var(--bg-card);
  border: 1px solid var(--hairline-strong);
  color: var(--text);
  box-shadow: 0 0.5rem 1.5rem rgba(15, 23, 42, 0.2);
  pointer-events: none;
  transform: translateX(-50%);
  animation: flash-toast-life 6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.flash-toast--alert {
  border-color: var(--red);
  color: var(--red);
}

@keyframes flash-toast-life {
  from { opacity: 0; transform: translateX(-50%) translateY(-0.5rem); }
  4%   { opacity: 1; transform: translateX(-50%) translateY(0); }
  92%  { opacity: 1; }
  to   { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .flash-toast { animation: flash-toast-hold 6s step-end forwards; }
  @keyframes flash-toast-hold {
    from { opacity: 1; }
    to   { opacity: 0; }
  }
}

/* Under 16px iOS Safari zooms the page to the focused field and leaves it
   zoomed — on the composer, the two places the product is judged. Every
   sheet sizes its own controls below that (0.9rem is the house size), so this
   is the one rule that has to win over all of them; maximum-scale is not the
   fix (it takes pinch-zoom from everyone). Chromium never auto-zooms, so
   bin/shots cannot show it; a phone can. */
@media (pointer: coarse) {
  input, textarea, select { font-size: 1rem !important; }
}
