/* ============================================================================
   material.css - the stamped white material, applied to this product's own
   components. Loaded AFTER components.css and overriding it.

   WHY THIS IS A SEPARATE FILE AND NOT A REWRITE OF components.css.
   components.css encodes Alex's instructions in its STRUCTURE: the three
   controls that must fit one row at 360px, the 44px tap floor, the pop-up whose
   body deliberately does not scroll, the folder text that wraps rather than
   truncates, the 16px font that stops iOS zooming a focused field. Every one of
   those was earned and several were found in a real browser. A rewrite would
   throw them away to change a colour.

   So this file changes only the SKIN - background, border, box-shadow, radius,
   colour - and the few places where the material genuinely needs a different
   box (the chat, the bar, the scroller). Law 2: it is addable, removable, and
   able never to have existed. Delete the one <link> and the product is exactly
   what it was.

   THE MATERIAL, which is identical in the IIS CRM and is the whole point:
     1. A WALL IS FOUR FLAT FACES, NOT A SWEEP. Every point along a straight wall
        faces the same direction, so it holds one tone; only the corners turn.
        A wall is therefore a real `border` - four widths, four colours - and
        the browser blends the corner arcs itself. A conic gradient along a flat
        wall is what makes this kind of work read as illustration.
     2. THE WIDTHS ARE UNEVEN AND THE UNEVENNESS IS DIAGONAL. The light is upper
        left and the eye is in the same corner, so a pit shows its top and left
        walls and a proud thing shows its bottom and right ones. Offsetting only
        vertically is the signature of a lamp directly overhead.
     3. A CIRCLE IS THE ONE EXCEPTION - no flat faces, so a conic sweep is
        correct there and nowhere else.
     4. DEPTH LIVES IN THE FALLOFF, NOT THE LINE. Every hard line is 1px; the
        occlusion blurs 7-18px from a low starting alpha.
     5. THE OCCLUSION INVERSION. The floor corner NEAREST the light is the
        DARKEST, because the rim is in the way.
     6. SHADOW LENGTH SCALES WITH HOW FAR A THING STANDS OFF ITS GROUND.
     7. NO PURE WHITE OR BLACK ON THE SURFACE.
   ============================================================================ */

/* ================================================== 1. THE TWO BUILDS ======
   Everything below is one of these two things, so they are defined once. */

/* ---- A PIT: something cut into the surface. */
.m-pit {
  position: relative;
  box-shadow:
    0 0 0 1px rgba(104, 108, 116, .3),
    0 1px 0 1px rgba(255, 255, 255, .75),
    0 2px 3px -1px rgba(255, 255, 255, .3);
}
/* ---- A FLOOR: the bottom of a pit, with its four walls as a real border. */
.m-floor, .rows, .card, .modal .body, .field input, .field textarea, .field select,
.searchbar input, .chat-log, .portal-frame, .tag, .tabs {
  border-style: solid;
  border-width: 5px 1px 2px 4px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
  background-clip: padding-box;
  background:
    /* THE INVERSION: nearest the light is darkest, because the rim is in the way */
    radial-gradient(135% 130% at 0% -8%,
      rgba(18, 20, 26, .24) 0%,
      rgba(18, 20, 26, .12) 30%,
      rgba(18, 20, 26, .04) 56%,
      rgba(18, 20, 26, 0) 76%),
    /* the left-to-right luminance ramp that gives depth of field */
    linear-gradient(101deg,
      rgba(18, 20, 26, .08) 0%,
      rgba(18, 20, 26, .022) 34%,
      rgba(255, 255, 255, 0) 62%,
      rgba(255, 255, 255, .07) 100%),
    linear-gradient(178deg, var(--floor-lo) 0%, var(--floor) 55%, var(--floor-hi) 100%);
  box-shadow:
    inset 0 1px 0 var(--cut),
    inset 1px 0 0 rgba(56, 60, 70, .5),
    inset 0 9px 11px -7px rgba(14, 16, 22, .4),
    inset 9px 0 11px -8px rgba(14, 16, 22, .32),
    inset 0 -1px 0 var(--catch),
    inset -1px 0 0 rgba(255, 255, 255, .5);
  transition: border-width var(--t), border-color var(--t), box-shadow var(--t);
}

/* ---- PROUD: something standing off the surface. The mirror of a pit. */
.m-proud, .row, .btn, .btn-bubble, .folder .sq, .copy, .info, .choice,
.btn-order, .tab, .modal {
  border-style: solid;
  border-width: 1px 4px 4px 1px;
  border-color: var(--key-top) var(--key-right) var(--key-bottom) var(--key-left);
  background-clip: padding-box;
  background:
    linear-gradient(101deg,
      rgba(255, 255, 255, .5) 0%,
      rgba(255, 255, 255, 0) 52%,
      rgba(20, 24, 32, .045) 100%),
    linear-gradient(178deg, var(--proud-hi) 0%, var(--proud) 60%, var(--proud-lo) 100%);
  /* the material's light neutral, UNDER the gradient and declared after the
     shorthand so it survives it. Rule 7 of the material: no pure white on the
     surface, so this is #edf0f5 and not #ffffff. */
  background-color: var(--paper);
  box-shadow: var(--shadow-1);
  transition: border-width var(--t), border-color var(--t),
              background var(--t), box-shadow var(--t), transform var(--t);
}

/* ---- STAMPED: a proud thing pressed flat. This is what a press LOOKS like,
   and it is the pit build at a proud thing's thickness. */
.m-stamped, .btn:active, .row:active, .choice[aria-checked="true"],
.copy:active, .folder:active .sq, .btn-order:active, .tab[aria-selected="true"] {
  border-width: 4px 1px 1px 4px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
  background:
    radial-gradient(135% 130% at 0% -8%,
      rgba(18, 20, 26, .26) 0%,
      rgba(18, 20, 26, .13) 30%,
      rgba(18, 20, 26, .04) 56%,
      rgba(18, 20, 26, 0) 76%),
    linear-gradient(101deg,
      rgba(18, 20, 26, .08) 0%, rgba(18, 20, 26, .022) 34%,
      rgba(255, 255, 255, 0) 62%, rgba(255, 255, 255, .07) 100%),
    linear-gradient(178deg, var(--floor-lo) 0%, var(--floor) 55%, var(--floor-hi) 100%);
  box-shadow:
    inset 0 1px 0 rgba(30, 34, 42, .82),
    inset 1px 0 0 rgba(62, 66, 76, .45),
    inset 0 7px 9px -6px rgba(14, 16, 22, .34),
    inset 7px 0 9px -7px rgba(14, 16, 22, .28),
    inset 0 -1px 0 var(--catch),
    inset -1px 0 0 rgba(255, 255, 255, .5);
}

/* ================================================== 2. THE PLANE ==========
   THE STAGE NEVER GROWS WITH ITS CONTENTS, and this is where that is decided
   for the whole product rather than per screen. Alex: "i dont like how the
   messages arent scrollable inside the stage, i dont like how the stage extends
   with the chat."

   The shell is the plane: exactly the viewport, never taller. The page is the
   ONLY thing that grows, and it is a bounded scroller. The bar is a flex child
   rather than `position: fixed`, so it is pinned by the layout rather than by
   being lifted out of it - which is what stops it floating over content or
   drifting when a screen is short. */
.shell {
  position: relative;
  height: 100vh;
  height: 100dvh;          /* so a phone's address bar cannot change the plane */
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;        /* THE PLANE IS A LID. Nothing may size it. */
  background:
    radial-gradient(135% 95% at 18% 2%,
      var(--stage-hi) 0%, var(--stage) 42%, var(--stage-lo) 100%);
}
/* GRAIN is the last 2 percent: one turbulence layer at low opacity, multiplied.
   It goes off in outdoor mode, because a multiply layer spends contrast. */
.shell::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: .028;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
  z-index: 0;
}
html.outdoor .shell::after { opacity: 0; }

.page {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  min-height: 0;            /* the line that makes a flex child scroll rather
                               than stretch its parent */
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  /* the bar is no longer fixed, so the page does not reserve room for it */
  padding-bottom: var(--s5);
}
@media (min-width: 760px) {
  .page { padding-bottom: var(--s5); }
}

/* ================================================== 3. WHERE YOU ARE ======
   The path line. Alex's smaller point, and the fix for being four folders deep
   with one Back button: every step of the path is a key, and the FIRST one is
   home, so home is one tap away without putting a Home button in the bar where
   it would duplicate navigation. */
.crumbs {
  position: relative; z-index: 1;
  flex: 0 0 auto;
  display: flex; align-items: center; gap: var(--s1);
  min-width: 0;
  padding: var(--s2) var(--gutter) 0;
  max-width: var(--maxw);
  width: 100%;
  margin: 0 auto;
}
.crumbs .sep-c {
  flex: 0 0 auto;
  color: var(--ink-faint);
  font-size: var(--t-tiny);
}
.crumb {
  border: 0; background: none; padding: 2px; margin: 0;
  font: inherit;
  font-size: var(--t-tiny); font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-faint);
  cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 14ch;
  min-height: 0;
}
/* NEVER SHRINK THE TARGET TO MATCH THE PAINT. His own line, and the pattern
   is the one `.info` and `.copy` already use in components.css: the crumb and
   the sun key PAINT small, as they must on a path line, and their tap target is
   expanded to 44px with an ::after. A 0px-tall control is a missed tap, and the
   path line is a control somebody uses with a thumb. */
.crumb, .sunkey { position: relative; }
.crumb::after, .sunkey::after {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: 50%;
  height: 44px;
  transform: translateY(-50%);
}
.crumb.here::after { content: none; }   /* not a control: it is where you are */

.crumb.here {
  color: var(--ink-strong);
  letter-spacing: .05em;
  max-width: 24ch;
  cursor: default;
}
@media (max-width: 560px) {
  /* on a phone only home and here survive, so the line never wraps */
  .crumb:not(.here):not(.first) { display: none; }
}

/* ================================================== 4. THE BOTTOM ROW =====
   NOT a second copy of the navigation. Alex: "i dont like how on the html, the
   bottom row buttons are just replacments for the main buttons, i think the
   bottom row should be like, settings, the company assistant, ect, things that
   are major that seperate from everything else."

   Before this pass the bar WAS the four sections. Now the four sections are
   folders on the home stage, and the bar carries the four things that sit
   outside the tree entirely: the assistant that can run the whole app, the one
   queue that needs a person, the settings, and the way out. */
.tabs {
  position: relative;          /* not fixed: a flex child of the plane */
  left: auto; right: auto; bottom: auto;
  z-index: 2;
  flex: 0 0 auto;
  height: auto;
  min-height: var(--tabbar);
  margin: 0 var(--gutter) var(--s2);
  border-radius: var(--radius);
  padding: var(--s1) var(--s2);
  padding-bottom: calc(var(--s1) + env(safe-area-inset-bottom, 0px));
  display: flex;
  gap: var(--s2);
  align-items: stretch;
  justify-content: center;
  max-width: var(--maxw);
  width: auto;
}
@media (min-width: 760px) {
  .tabs {
    position: relative; top: auto;
    border-top: 0; border-bottom: 0;
    height: auto;
    margin: 0 auto var(--s3);
    width: max-content;
  }
}
.tab {
  flex: 0 1 auto;
  min-width: 72px;
  min-height: 46px;
  border-radius: var(--radius-sm);
  padding: var(--s1) var(--s2);
  color: var(--ink-key);
  font-size: 11px; font-weight: 700;
  letter-spacing: .06em;
  gap: 2px;
}
.tab .ico { font-size: 17px; }
/* the selected key is PRESSED IN, which is the material's own way of saying
   "you are here" - no underline, no colour swap */
.tab[aria-selected="true"] { color: var(--ink-strong); }
/* the assistant is the one primary key in the bar, so it carries the accent */
.tab.primary {
  border-color: var(--accent-top) var(--accent-right) var(--accent-bottom) var(--accent-left);
  background:
    linear-gradient(101deg, rgba(255,255,255,.3) 0%, rgba(255,255,255,0) 52%, rgba(0,0,0,.09) 100%),
    linear-gradient(178deg, var(--accent-hi) 0%, var(--accent) 60%, var(--accent-lo) 100%);
  /* AFTER the shorthand, never before: `background` resets
     `background-color` to transparent, so a flat colour declared above it
     is thrown away. Measured by prove-ui, which reads the computed style
     rather than the source - and the source looked right. */
  background-color: var(--accent);
  color: var(--accent-ink);
  text-shadow: var(--accent-shadow);
}
.tab.primary[aria-selected="true"] {
  border-width: 4px 1px 1px 4px;
  border-color: var(--accent-lo) var(--accent-top) var(--accent-top) var(--accent-lo);
}
/* THE COUNT ON THE BELL. Notifications live here and nowhere else - Alex,
   2026-10-24: "the needs you seciton should just be notifications, not at the
   top of the homepage." */
.tab { position: relative; }
.tab .badge {
  position: absolute; top: -4px; right: -4px;
  min-width: 17px; padding: 1px 4px;
  border-radius: var(--radius-pill);
  background: var(--alert); color: var(--alert-ink);
  font-size: 10px; font-weight: 700;
  text-shadow: none;
  z-index: 2;
}

/* ================================================== 5. HOME, THE STAGE ====
   The four sections as folders on a surface, which is what makes the bar able
   to stop being navigation. Straight off the approved lab sheet: the icon is
   75 percent of its column, the wall is thinned because the object is small,
   the label wraps rather than clips, and the proud build swaps to the pit build
   under a thumb. */
.folders { gap: var(--s4) var(--s2); }
.folder .sq {
  width: 74%;
  margin: 0 auto;
  border-width: 1px 3px 3px 1px;
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
  color: var(--ink-soft);
  font-size: 26px;
}
.folder:active .sq { box-shadow: var(--shadow-1); transform: none; }
.folder .txt { color: var(--ink-soft); font-weight: 600; }
/* the live mark: the one place the material glows, saying the assistant has an
   answer waiting under here */
.folder { position: relative; }
.folder .live {
  position: absolute; top: -2px; right: 12%;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--live);
  box-shadow: 0 0 5px var(--live), 0 0 12px var(--live-glow);
  animation: m-float 2.6s ease-in-out infinite;
}
@keyframes m-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }

/* ================================================== 6. ROWS AND WELLS =====
   A list is a pit with proud slabs lying in it, so a row reads as an object you
   can pick up - which is what his long-press-to-drag gesture implies. */
.rows {
  border-radius: var(--radius);
  padding: var(--s2);
  display: flex; flex-direction: column; gap: 6px;
  overflow: visible;
}
.row {
  border-radius: var(--radius-sm);
  min-height: 42px;
  padding: var(--s2) var(--s3);
  color: var(--ink);
}
.row:last-child { border-bottom: 1px solid; border-bottom-color: var(--key-bottom); }
.row .label { color: var(--ink); font-weight: 580; }
.row .value { color: var(--ink-soft); }
.row .chev { color: var(--ink-faint); }
.row.stop .label { color: var(--stop); }
/* a row with nothing behind it yet is FLUSH with the surface: not proud,
   because it is not a thing you can press */
.row.soon {
  border-width: 1px;
  border-color: var(--line);
  background: none;
  box-shadow: none;
}
/* THE ONE LOUD THING. An accent reserved for "this is wrong", used nowhere
   else, so it reads as wrong from across the room. */
.row.late, .card.late {
  border-left-width: 3px;
  border-left-color: var(--alert);
}
.row.late .value, .card.late .meta.late { color: var(--alert); font-weight: 650; }

.card {
  border-radius: var(--radius);
  padding: var(--s4);
}
.card .meta { color: var(--ink-soft); }

.group > h3 { color: var(--ink-faint); }

/* ================================================== 7. KEYS ===============
   A button is a key you press: proud, and it stamps flat while held rather than
   scaling, because a key does not get smaller when you press it. */
.btn {
  border-radius: var(--radius-sm);
  color: var(--ink-key);
  font-weight: 650;
}
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: 1; color: var(--ink-faint); box-shadow: none; }
.btn[disabled]:active { border-width: 1px 4px 4px 1px; }

/* Instruction 51: accept, continue, confirmed, save HAVE COLOUR - and they are
   still machined out of the same material. Only the faces change. */
.btn.go {
  border-color: var(--accent-top) var(--accent-right) var(--accent-bottom) var(--accent-left);
  /* THE FLAT COLOUR UNDER THE GRADIENT. Not decoration: a gradient that fails
     to parse leaves a transparent button, and a button whose colour carries
     meaning must not be able to lose it. It is also what makes "is this blue"
     answerable by reading one property instead of rasterising the page. */
  background:
    linear-gradient(101deg, rgba(255,255,255,.3) 0%, rgba(255,255,255,0) 52%, rgba(0,0,0,.1) 100%),
    linear-gradient(178deg, var(--accent-hi) 0%, var(--accent) 60%, var(--accent-lo) 100%);
  /* AFTER the shorthand, never before: `background` resets
     `background-color` to transparent, so a flat colour declared above it
     is thrown away. Measured by prove-ui, which reads the computed style
     rather than the source - and the source looked right. */
  background-color: var(--accent);
  color: var(--accent-ink);
  text-shadow: var(--accent-shadow);
}
.btn.go:active {
  border-width: 4px 1px 1px 4px;
  border-color: var(--accent-lo) var(--accent-top) var(--accent-top) var(--accent-lo);
}
/* Instruction 19: cancel is WHITE and sits immediately LEFT of save. */
.btn.cancel { color: var(--ink-key); }
/* Instruction 52: cancel subscription, exit, sign out, delete - RED. */
.btn.stop { color: var(--stop); }
.btn.stop.filled {
  border-color: #e0697a #8d1d2a #6f1621 #d4566a;
  background:
    linear-gradient(101deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,0) 52%, rgba(0,0,0,.12) 100%),
    linear-gradient(178deg, #d1465a 0%, var(--stop) 60%, #9d1f2f 100%);
  /* AFTER the shorthand, never before: `background` resets
     `background-color` to transparent, so a flat colour declared above it
     is thrown away. Measured by prove-ui, which reads the computed style
     rather than the source - and the source looked right. */
  background-color: var(--stop);
  color: #fff;
  text-shadow: 0 1px 0 rgba(0, 0, 0, .3);
}
.btn.small { border-width: 1px 3px 3px 1px; }
.btn.small:active { border-width: 3px 1px 1px 3px; }

/* Instruction 14: "text in a bubble with a blue plus in a circle next to the
   text". The bubble is proud; the plus is the ONE place a conic sweep belongs,
   because a circle has no flat faces. */
.btn-bubble {
  border-radius: var(--radius-pill);
  color: var(--ink-key);
}
.btn-bubble:active {
  transform: translateY(1px);
  border-width: 4px 1px 1px 4px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
}
.btn-bubble .plus {
  background:
    radial-gradient(120% 120% at 26% 14%, var(--accent-hi) 0%, var(--accent) 50%, var(--accent-lo) 100%);
  /* AFTER the shorthand, never before: `background` resets
     `background-color` to transparent, so a flat colour declared above it
     is thrown away. Measured by prove-ui, which reads the computed style
     rather than the source - and the source looked right. */
  background-color: var(--accent);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .5),
    inset 0 -1px 0 rgba(0, 0, 0, .25),
    0 1px 2px rgba(20, 30, 60, .4);
  text-shadow: var(--accent-shadow);
}

.btn-order { border-radius: var(--radius-sm); color: var(--ink-soft); }
.copy { border-radius: var(--radius-sm); color: var(--ink-soft); }
.copy.copied {
  border-color: #8fd5a8 #2f6f46 #255a38 #7cc998;
  background: linear-gradient(178deg, #d9f5e3 0%, var(--done-soft) 60%, #c9eed7 100%);
  color: #10622f;
}

/* the (i): a small proud disc. Its 44px tap target is in components.css and is
   not touched here. */
.info { border-width: 1px 2px 2px 1px; border-radius: 50%; color: var(--ink-soft); }
.info[aria-expanded="true"] {
  border-width: 2px 1px 1px 2px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
  background: linear-gradient(178deg, var(--floor-lo), var(--floor));
  color: var(--accent);
}

/* ================================================== 8. FIELDS =============
   A field is a pit, and it is cut DEEPER while it has focus - which is the
   material's own way of saying "the caret is here". */
.field input, .field textarea, .field select,
.searchbar input, .chat-input {
  border-radius: var(--radius-sm);
  color: var(--ink);
  text-shadow: 0 1px 0 rgba(255, 255, 255, .6);
}
.field input:focus, .field textarea:focus, .field select:focus,
.searchbar input:focus, .chat-input:focus {
  outline: 0;
  border-width: 6px 1px 1px 5px;
  border-top-color: var(--wall-top-deep);
  border-left-color: var(--wall-left-deep);
  box-shadow:
    inset 0 1px 0 rgba(16, 18, 24, .95),
    inset 1px 0 0 rgba(44, 48, 58, .6),
    inset 0 13px 15px -7px rgba(10, 12, 18, .48),
    inset 13px 0 15px -8px rgba(10, 12, 18, .4),
    inset 0 -1px 0 var(--catch),
    inset -1px 0 0 rgba(255, 255, 255, .5);
}
.field label { color: var(--ink-soft); }
::placeholder { color: var(--ink-faint); }

/* ================================================== 9. TAGS, SEPARATORS ===
   A tag is a word cut into the surface, not a sticker on it. */
.tag {
  border-width: 2px 1px 1px 2px;
  border-radius: var(--radius-pill);
  color: var(--ink-soft);
  padding: 2px var(--s2);
}
.tag.go { color: var(--accent); }
.tag.done { color: var(--done); }
.tag.stop { color: var(--stop); }
.tag.warn { color: var(--warn); }

/* a carved line: one dark line with a light catch under it, which is what a
   scored groove in a surface actually looks like */
.sep {
  height: 0;
  background: none;
  border: 0;
  border-top: 1px solid rgba(40, 46, 60, .32);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .85);
}

/* ================================================== 10. MODAL =============
   A pop-up stands well off the surface, so it gets the longest shadow tier.
   Its body stays NOT scrollable - instruction 18 - and that is in
   components.css, untouched. */
.scrim { background: rgba(8, 10, 16, .6); }
.modal {
  border-width: 1px 6px 6px 1px;
  border-radius: var(--radius);
  box-shadow: var(--shadow-pop);
}
.modal header { border-bottom: 1px solid rgba(40, 46, 60, .26); box-shadow: 0 1px 0 rgba(255,255,255,.8); }
.modal footer { border-top: 1px solid rgba(40, 46, 60, .26); box-shadow: inset 0 1px 0 rgba(255,255,255,.8); }
.modal .body { border-width: 0; background: none; box-shadow: none; }

.choice { border-radius: var(--radius-sm); color: var(--ink); }
.choice[aria-checked="true"] { color: var(--ink-strong); }
.choice .dot {
  border: 0;
  background:
    radial-gradient(120% 120% at 30% 20%, var(--floor-hi), var(--floor-lo));
  box-shadow:
    inset 0 1px 0 var(--cut),
    inset 0 4px 5px -3px rgba(14, 16, 22, .45),
    inset 0 -1px 0 var(--catch);
}
.choice[aria-checked="true"] .dot {
  background: radial-gradient(120% 120% at 30% 20%, var(--accent-hi), var(--accent-lo));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .45),
    inset 0 -1px 0 rgba(0, 0, 0, .3),
    0 1px 2px rgba(20, 30, 60, .4);
}

/* ================================================== 11. FEEDBACK ==========
   UNDO INSTEAD OF "ARE YOU SURE". A dialog on a phone, in gloves, is a tax on
   every action to catch the rare mistake, so the thing happens and this rises
   for a few seconds carrying the way back. It is a strip cut into the plane
   rather than a dark pill floating over it. */
.toast {
  bottom: calc(var(--tabbar) + var(--s4) + env(safe-area-inset-bottom, 0px));
  border-radius: var(--radius-sm);
  border-style: solid;
  border-width: 5px 1px 2px 4px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
  background-clip: padding-box;
  background: linear-gradient(178deg, var(--floor-lo) 0%, var(--floor) 55%, var(--floor-hi) 100%);
  box-shadow:
    inset 0 1px 0 var(--cut),
    inset 0 9px 11px -7px rgba(14, 16, 22, .4),
    inset 0 -1px 0 var(--catch),
    0 2px 2px rgba(0, 0, 0, .3),
    0 14px 22px -10px rgba(10, 14, 22, .5);
  color: var(--ink);
  display: flex; align-items: center; gap: var(--s3);
}
.toast.bad { border-top-color: var(--alert); color: var(--alert); }
.toast .undo {
  flex: 0 0 auto;
  min-height: 32px; padding: 0 var(--s3);
  border-radius: var(--radius-sm);
  border-style: solid; border-width: 1px 3px 3px 1px;
  border-color: var(--key-top) var(--key-right) var(--key-bottom) var(--key-left);
  background: linear-gradient(178deg, var(--proud-hi), var(--proud-lo));
  color: var(--ink-key);
  font-size: var(--t-tiny); font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  cursor: pointer;
}
.toast .undo:active { border-width: 3px 1px 1px 3px; border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left); }

/* the (i) popover stays a LAYER ABOVE the material rather than another panel,
   so it is the one dark thing on the page and reads as floating */
.info-pop {
  /* A TOOLTIP MUST NEVER SWALLOW A PRESS. It holds one sentence and nothing to
     interact with, so it does not take the pointer: the press reaches the
     control underneath and the popover still closes, because the document
     listener sees the event either way.

     Found by prove-ui in a real browser after this pass removed the desktop top
     bar: content starts higher now, so a popover near the top flips BELOW onto
     the next control, and every press there was being eaten. */
  pointer-events: none;
  background: #14171c;
  color: #eef1f5;
  border: 1px solid #2b313a;
  box-shadow: var(--shadow-pop);
}
.info-pop, .info-pop * { text-shadow: none; }

/* ================================================== 12. EMPTY IS TEACHING =
   His rule 9: no label that cannot be acted on. An empty state names the ONE
   thing to do and is itself the control. In the material it is a shallow dish,
   so it reads as a place where something belongs rather than as a gap. */
.empty {
  color: var(--ink-soft);
  border-radius: var(--radius);
  border-style: solid;
  border-width: 4px 1px 1px 3px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
  background-clip: padding-box;
  background: linear-gradient(178deg, var(--floor-lo) 0%, var(--floor) 60%, var(--floor-hi) 100%);
  box-shadow:
    inset 0 1px 0 var(--cut),
    inset 0 8px 10px -7px rgba(14, 16, 22, .34),
    inset 0 -1px 0 var(--catch);
}
.empty h3 { color: var(--ink-strong); }

.pickbar {
  border-radius: var(--radius-sm);
  border-style: solid;
  border-width: 4px 1px 1px 3px;
  border-color: var(--accent) var(--wall-right) var(--wall-bottom) var(--accent);
  background: linear-gradient(178deg, var(--floor-lo), var(--floor-hi));
  box-shadow: inset 0 1px 0 var(--cut), inset 0 -1px 0 var(--catch);
  color: var(--ink);
}
.row.picked, .folder.target .sq { outline: 2px solid var(--accent); outline-offset: 2px; }

.portal-frame { border-radius: var(--radius); }

/* ============================================================================
   13. THE CHAT

   All four of his chat complaints were one complaint: the conversation was
   driving the stage.

     1. THE STAGE NEVER GROWS. `.shell` is exactly the viewport and
        `overflow: hidden`, and the chat screen is a flex column inside the page
        at a bounded height. The old rule was `max-height: 46vh` on the log,
        which bounds the LOG against the VIEWPORT while everything around it
        still grows the page - so the composer walked down the screen as the
        conversation got longer.
     2. THE MESSAGES SCROLL, INSIDE. `.chat-log` is `flex: 1 1 auto` with
        `min-height: 0`, which is the line that actually makes a flex child
        scroll instead of stretching its parent.
     3. IT READS AS A CONVERSATION. Yours are proud slabs on the right, the
        assistant's are cut into the floor on the left, each at 78 percent so
        the two sides are visibly two sides, with the speaker's name only when
        it changes. The old bubbles were `var(--accent-soft, #eef)` and
        `var(--panel-2, #f4f4f5)` - two tokens that were never defined, so the
        product was painting a hardcoded lavender and a hardcoded grey that
        ignored the theme entirely.
     4. CONTEXT IS A SHELF YOU CAN DROP ONTO, PER ASSISTANT. Drag a file
        anywhere onto the stage and the whole log becomes a drop pit.
   ============================================================================ */
.card.chat {
  display: flex;
  flex-direction: column;
  /* bounded by the SURFACE it is in, not by the viewport */
  height: 100%;
  min-height: 0;
  padding: 0;
  overflow: hidden;
  border-radius: var(--radius);
}
/* the screen that holds the chat gives it the whole surface and stops the
   surface scrolling, so there is exactly one scroller on this screen */
.page.chatting { overflow: hidden; display: flex; flex-direction: column; }
.page.chatting > .chat-wrap {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: var(--s2);
  width: 100%; max-width: var(--maxw); margin: 0 auto;
  padding: 0 var(--gutter);
}

/* the shelf: this assistant's documents */
.chat-shelf {
  flex: 0 0 auto;
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2);
  padding: var(--s2);
  border-radius: var(--radius-sm);
  border-style: solid; border-width: 4px 1px 1px 3px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
  background-clip: padding-box;
  background: linear-gradient(178deg, var(--floor-lo), var(--floor-hi));
  box-shadow: inset 0 1px 0 var(--cut), inset 0 -1px 0 var(--catch);
}
.chat-shelf .what {
  font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-faint);
}
.chat-shelf .none { font-size: var(--t-tiny); color: var(--ink-faint); }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 100%;
  padding: 4px var(--s2);
  border-radius: var(--radius-sm);
  border-style: solid; border-width: 1px 3px 3px 1px;
  border-color: var(--key-top) var(--key-right) var(--key-bottom) var(--key-left);
  background: linear-gradient(178deg, var(--proud-hi), var(--proud-lo));
  box-shadow: var(--shadow-1);
  font-size: var(--t-tiny); font-weight: 600;
  color: var(--ink);
}
.chip .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 15ch; }
.chip .x {
  border: 0; background: none; padding: 0; margin: 0;
  color: var(--ink-faint); cursor: pointer; font-size: 14px; line-height: 1;
}

/* THE LOG IS THE ONLY SCROLLER ON THE SCREEN. */
.chat-log {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;          /* was 46vh: the viewport is not the stage */
  border-radius: var(--radius);
  padding: var(--s3);
  gap: 6px;
  /* NOT smooth. A chat jumps to the newest line; it does not glide there.
     Measured in Chrome: with scroll-behavior:smooth a programmatic jump to the
     bottom animates, a message arriving mid-animation restarts it, and the log
     settles short of the newest message every time. */
  scroll-behavior: auto;
  overscroll-behavior: contain;
}
.chat-msg {
  max-width: 78%;
  border-radius: var(--radius-sm);
  padding: var(--s2) var(--s3);
  background: none;
}
.chat-msg .who {
  display: block; margin-bottom: 2px;
  font-size: 10px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-faint);
}
.chat-msg .at { display: block; margin-top: 3px; font-size: 10px; color: var(--ink-faint); }
.chat-msg p { color: var(--ink); font-size: var(--t-small); line-height: 1.5; }
/* mine: proud, standing off the floor, on the right */
.chat-msg.mine {
  border-style: solid; border-width: 1px 3px 3px 1px;
  border-color: var(--key-top) var(--key-right) var(--key-bottom) var(--key-left);
  background: linear-gradient(178deg, var(--proud-hi), var(--proud-lo));
  box-shadow: var(--shadow-1);
}
/* theirs: cut INTO the floor, on the left */
.chat-msg.theirs {
  border-style: solid; border-width: 3px 1px 1px 3px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
  background-clip: padding-box;
  background: linear-gradient(178deg, var(--floor-lo), var(--floor-hi));
  box-shadow: inset 0 1px 0 var(--cut), inset 0 6px 8px -6px rgba(14,16,22,.3), inset 0 -1px 0 var(--catch);
}
.chat-msg.thinking { display: flex; gap: 5px; padding: var(--s3); }
.chat-msg.thinking p { display: none; }
.chat-msg.thinking i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--ink-faint);
  animation: m-dot 1.1s ease-in-out infinite;
}
.chat-msg.thinking i:nth-child(2) { animation-delay: .14s; }
.chat-msg.thinking i:nth-child(3) { animation-delay: .28s; }
@keyframes m-dot { 0%, 100% { opacity: .3; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-2px); } }

/* a tool turn is evidence, not conversation: a quiet line down the middle */
.chat-did { color: var(--ink-faint); font-size: var(--t-tiny); }

.chat-bar {
  flex: 0 0 auto;
  border-top: 0;
  padding: 0;
  gap: var(--s2);
  padding-bottom: var(--s2);
}
.chat-input { border-radius: var(--radius-sm); }

/* THE DROP TARGET. The whole log becomes one while something is over it. */
.chat-wrap { position: relative; }
.chat-drop {
  position: absolute; inset: 0;
  z-index: 5;
  display: none;
  place-items: center;
  padding: var(--s4);
  text-align: center;
  border-radius: var(--radius);
  border-style: solid; border-width: 5px 1px 2px 4px;
  border-color: var(--accent) var(--wall-right) var(--wall-bottom) var(--accent);
  background: linear-gradient(178deg, var(--floor-lo), var(--floor-hi));
  box-shadow: inset 0 1px 0 var(--cut), inset 0 10px 12px -7px rgba(14,16,22,.42);
  color: var(--ink);
  font-size: var(--t-small);
}
.chat-wrap.dragging .chat-drop { display: grid; }

/* ================================================== 14. THE SUN KEY =======
   Outdoor mode has to be reachable while standing in the sun, not four folders
   deep in Settings. */
.sunkey {
  flex: 0 0 auto;
  min-height: 34px; padding: 0 var(--s2);
  border-radius: var(--radius-sm);
  border-style: solid; border-width: 1px 3px 3px 1px;
  border-color: var(--key-top) var(--key-right) var(--key-bottom) var(--key-left);
  background: linear-gradient(178deg, var(--proud-hi), var(--proud-lo));
  box-shadow: var(--shadow-1);
  color: var(--ink-soft);
  font-size: var(--t-tiny); font-weight: 650;
  cursor: pointer;
}
.sunkey:active {
  border-width: 3px 1px 1px 3px;
  border-color: var(--wall-top) var(--wall-right) var(--wall-bottom) var(--wall-left);
}
html.outdoor .sunkey { color: var(--ink-strong); }
