/*
 * Buffalo147 AI — chat workspace
 *
 * Three regions: a history rail on the trailing edge, the conversation in the
 * middle, notices floating on the leading edge. The layout is a fixed-height
 * grid rather than a scrolling page, because a chat app whose composer drifts
 * off the bottom of the screen is unusable.
 */

/*
 * The shell's geometry is no longer in this file.
 *
 * `.bf-chat-page`, `.bf-app`, `.bf-rail` and `.bf-main` — the grid and its
 * two tracks — moved to `shell.css`, which is small and render-blocking.
 * This file is not: it is fetched without holding up the paint, and a page
 * drawn before it arrives now has its layout anyway.
 *
 * Moved, not copied. If you need to change the grid, change it there.
 */



/* Ambient warmth, matching the auth screens. */
.bf-app::before {
  content: '';
  position: absolute;
  inset-block-start: -25%;
  inset-inline-start: 8%;
  width: 60vw; height: 60vw;
  max-width: 780px; max-height: 780px;
  background: radial-gradient(circle, rgba(169, 79, 49,.07) 0%, transparent 62%);
  pointer-events: none;
  z-index: var(--bf-z-behind);
}

/* ---------------------------------------------------------------------
 * History rail
 * ------------------------------------------------------------------ */


/*
 * Only the conversation list may shrink. Without this the footer took its
 * share of the squeeze and the account card lost its bottom line — visible
 * in the corner of the screen, unreadable.
 */
.bf-rail__head,
.bf-new-chat,
.bf-rail__search,
/* The top bar and the rail footer are in `shell-layout.css` too:
   they arrange children that image.css already styles, and that
   sheet blocks while this one does not. Moved, not copied. */

/*
 * The rail's head: the site's name, and a way out on a phone.
 *
 * The burger is hidden where the rail cannot be closed — on a desktop
 * it is a control that points at nothing.
 */
.bf-rail__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 6px 4px 2px;
}

.bf-rail__logo {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  object-fit: cover;
}

.bf-rail__names { display: grid; gap: 2px; min-width: 0; }

.bf-rail__names strong {
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -.2px;
  color: var(--text-primary);
  white-space: nowrap;
}

.bf-rail__names span { font-size: 12px; color: var(--text-muted); }

.bf-rail__head {
  display: flex;
  align-items: center;
  gap: 8px;
}

/*
 * The burger, only where the rail can be closed.
 *
 * On a desktop the rail is always open, so the control points at
 * nothing. Declared after `.bf-icon-btn`, which sets `inline-flex` and
 * would otherwise win on source order alone.
 */
@media (min-width: 861px) {
  .bf-rail .bf-rail__burger { display: none; }
}

.bf-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  flex: none;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--bf-radius-sm);
  background: var(--bf-glass);
  color: var(--bf-text-muted);
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease), color var(--bf-fast) var(--bf-ease);
}
.bf-icon-btn:hover { background: var(--bf-glass-strong); color: var(--bf-text); }

/*
 * A THUMB NEEDS FORTY-FOUR PIXELS, WHATEVER THE PICTURE IS.
 *
 * These are 38px, and a narrow screen takes them down to 34 — smaller on
 * the one device where they are pressed with a thumb rather than clicked
 * with a pointer. Measured at 360px: the button that opens the rail came
 * out 38 wide, under the forty nobody argues about.
 *
 * The drawing is not changed. A circle that suddenly becomes a lozenge to
 * satisfy a number is a worse interface, and the number is about where a
 * press lands, not about what is on the screen. So the target is grown
 * and the button is left alone.
 *
 * `hover: none` rather than a width, because this is about the hand, not
 * the screen: a small laptop window has a pointer and needs nothing, and
 * a large phone has a thumb and needs it.
 */
@media (hover: none) {
  /*
   * THE WHOLE FAMILY, NOT THE ONE THAT WAS LOOKED AT.
   *
   * 3.85.0 grew this area for `.bf-icon-btn` and stopped there, because
   * the harness rendered the rail, the topbar, the menu, the cards, the
   * shelf and the pricing — and not the composer, which is the one screen
   * touched on every single visit. Rendering it measured the attach and
   * microphone buttons at 38 wide and both chips at 38 tall, on a phone,
   * where a thumb is the only thing there is.
   */
  .bf-icon-btn,
  .bf-input__btn,
  .bf-depth__btn { position: relative; }

  .bf-icon-btn::after,
  .bf-input__btn::after,
  .bf-depth__btn::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    /* Never smaller than the button itself, so a big control keeps its
       own area rather than being shrunk to this one. */
    min-width: 100%;
    min-height: 100%;
    transform: translate(-50%, -50%);
  }
}

.bf-new-chat {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--bf-space-2);
  width: 100%;
  padding: 14px 20px;
  border: 0;
  border-radius: var(--bf-radius-xs);
  /*
   * Outlined, not filled.
   *
   * Starting a conversation is the way in, not the thing being sold. A
   * rail whose first button is the loudest object on screen makes
   * everything after it read as quieter than it is.
   */
  /*
   * A deep copper fill.
   *
   * Dark enough that the rail still reads as part of the page, warm
   * enough that the way in is obvious. Not the bright gradient of a
   * primary action — that belongs to the one button that costs credit.
   */
  /*
   * The same orange as the send button.
   *
   * Two ways in — starting a conversation and sending a message — should
   * not be two different oranges; the eye reads that as two different
   * kinds of thing.
   */
  /*
   * #A94F31, and it stays #A94F31.
   *
   * The fill was already the accent, but a 15% white sheen lifted the
   * crown to #B76B52 — a shade off the word "سلام" and off the generate
   * button, on the same screen. Measured down the face: 43 points away
   * at the top, zero everywhere else.
   *
   * The sheen stays, faintly, because a flat fill is what makes a
   * button look ordinary — it just no longer leaves the colour.
   */
  background:
    linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0) 34%),
    var(--orange-500);
  /*
   * No halo, and squarer corners.
   *
   * The border was a pale warm line at half opacity, which against the
   * button's own colour read as a glow around the edge rather than an
   * edge. It is the accent's own darker step now, so the button has a
   * boundary without appearing lit from behind.
   */
  border: 1px solid var(--orange-600);
  color: var(--bf-on-accent);
  box-shadow: none;
}
.bf-new-chat:hover {
  border-color: var(--orange-500);
  background:
    linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,0) 34%),
    linear-gradient(180deg, #B76B52 0%, #A94F31 50%, #A94F31 100%);
}

.bf-rail__search {
  display: flex;
  align-items: center;
  gap: var(--bf-space-2);
  padding: 0 14px;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-md);
  background: var(--bf-surface-2);
  color: var(--bf-text-faint);
}
.bf-rail__search input {
  flex: 1;
  min-width: 0;
  padding: 11px 0;
  border: 0;
  background: none;
  color: var(--bf-text);
  font-family: inherit;
  font-size: var(--bf-size-base);
}
.bf-rail__search input:focus { outline: none; }
.bf-rail__search input::placeholder { color: var(--bf-text-faint); }
.bf-rail__search input::-webkit-search-cancel-button { display: none; }

.bf-rail__list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  margin-inline: calc(var(--bf-space-2) * -1);
  padding-inline: var(--bf-space-2);
}

.bf-rail__group { margin-bottom: var(--bf-space-4); }
.bf-rail__group h2 {
  margin: 0 0 var(--bf-space-2);
  padding-inline-start: 10px;
  font-size: var(--bf-size-xs);
  font-weight: 500;
  color: var(--bf-text-faint);
}

.bf-thread {
  display: flex;
  align-items: center;
  border-radius: var(--bf-radius-sm);
  transition: background var(--bf-fast) var(--bf-ease);
}
.bf-thread:hover,
.bf-thread.is-active { background: #151515; }

.bf-thread__open {
  flex: 1;
  min-width: 0;
  padding: 10px 12px;
  border: 0;
  background: none;
  color: var(--bf-text-muted);
  font-family: inherit;
  font-size: var(--bf-size-base);
  text-align: start;
  cursor: pointer;
}
.bf-thread:hover .bf-thread__open,
.bf-thread.is-active .bf-thread__open { color: var(--bf-text); }

.bf-thread__title {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bf-thread__more {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  margin-inline-end: 6px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: var(--bf-radius-xs);
  background: none;
  color: var(--bf-text-dim);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--bf-fast) var(--bf-ease), background var(--bf-fast) var(--bf-ease);
}
.bf-thread:hover .bf-thread__more,
.bf-thread.is-open .bf-thread__more { opacity: 1; }
.bf-thread__more:hover { background: var(--bf-glass-strong); color: var(--bf-text); }

.bf-rail__empty {
  text-align: center;
  padding-block: var(--bf-space-10);
  color: var(--bf-text-faint);
  margin: var(--bf-space-4) 0;
  padding: 0 var(--bf-space-4);
  font-size: var(--bf-size-sm);
}
.bf-rail__empty svg { margin: 0 auto var(--bf-space-3); display: block; }
.bf-rail__empty p { font-size: var(--bf-size-sm); margin: 0; }


.bf-upgrade {
  display: flex;
  align-items: center;
  gap: var(--bf-space-3);
  padding: 14px 16px;
  border: 1px solid var(--bf-accent-line);
  border-radius: var(--bf-radius-md);
  background: linear-gradient(135deg, rgba(169, 79, 49,.12), rgba(169, 79, 49,.03));
  color: var(--bf-text);
  transition: border-color var(--bf-fast) var(--bf-ease);
}
.bf-upgrade:hover { border-color: var(--bf-accent); color: var(--bf-text); }
.bf-upgrade__spark { color: var(--bf-accent); flex: none; }
.bf-upgrade__body { display: grid; gap: 3px; min-width: 0; }
.bf-upgrade__body strong { font-size: var(--bf-size-sm); font-weight: 500; }
.bf-upgrade__body em { font-style: normal; font-size: var(--bf-size-xs); color: var(--bf-accent); }

.bf-account { position: relative; }

.bf-account__btn {
  display: flex;
  align-items: center;
  gap: var(--bf-space-3);
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-md);
  background: var(--bf-surface-2);
  color: var(--bf-text);
  font-family: inherit;
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease);
}
.bf-account__btn:hover { background: var(--bf-surface-3); }

.bf-account__avatar { width: 34px; height: 34px; border-radius: 50%; flex: none; }
.bf-account__text { flex: 1; min-width: 0; display: grid; gap: 2px; text-align: start; }
.bf-account__text strong {
  font-size: var(--bf-size-sm); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/*
 * A quiet second line.
 *
 * It carried the accent when it held the balance — a figure worth
 * finding. What it says now is context, not a number to act on, so it
 * takes the muted grey the rest of the rail uses.
 */
.bf-account__text em {
  font-style: normal;
  font-size: var(--bf-size-xs);
  color: var(--text-muted);
}
.bf-account__chev { flex: none; color: var(--bf-text-dim); transition: transform var(--bf-fast) var(--bf-ease); }
.bf-account.is-open .bf-account__chev { transform: rotate(180deg); }

/* ---------------------------------------------------------------------
 * Menus
 * ------------------------------------------------------------------ */

.bf-menu {
  position: absolute;
  z-index: var(--bf-z-panel);
  min-width: 190px;
  padding: 6px;
  border: 1px solid var(--bf-line-strong);
  border-radius: var(--bf-radius-md);
  background: var(--bf-surface-2);
  box-shadow: var(--bf-shadow-lg);
  animation: bf-pop var(--bf-fast) var(--bf-ease-out);
}

@keyframes bf-pop {
  from { opacity: 0; transform: translateY(-5px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

.bf-menu a,
.bf-menu button {
  display: flex;
  align-items: center;
  gap: var(--bf-space-2);
  width: 100%;
  padding: 10px 12px;
  border: 0;
  border-radius: var(--bf-radius-xs);
  background: none;
  color: var(--bf-text-muted);
  font-family: inherit;
  font-size: var(--bf-size-base);
  text-align: start;
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease), color var(--bf-fast) var(--bf-ease);
}
.bf-menu a:hover,
.bf-menu button:hover { background: var(--bf-glass-strong); color: var(--bf-text); }

.bf-menu__danger { color: var(--bf-danger) !important; }
.bf-menu__danger:hover { background: var(--bf-danger-soft) !important; }

.bf-account__menu { inset-block-end: calc(100% + 8px); inset-inline: 0; }
.bf-thread__menu { position: fixed; }

/*
 * Menus open inward, never outward.
 *
 * The ⋮ button sits at the leading edge of the top bar. Anchoring the menu by
 * its inline-start edge made it grow away from the screen, so most of it —
 * including the destructive action — ended up outside the viewport. Anchoring
 * the opposite edge makes it grow back across the page instead.
 */
.bf-more__menu {
  inset-block-start: calc(100% + 8px);
  inset-inline-start: auto;
  inset-inline-end: 0;
}

/* ---------------------------------------------------------------------
 * Top bar
 * ------------------------------------------------------------------ */





/*
 * The mark shows where the rail is closed, and hides where it is open.
 *
 * It was `none` by default and only appeared above 900px — the opposite
 * of what it is for. With the rail open the site's name sits at its
 * head, so a mark beside it answers a question nobody asked; with the
 * rail closed it is the only thing that says where you are.
 */
.bf-topbar__brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--bf-text);
  font-weight: 700;
  font-size: var(--bf-size-base);
  flex: none;
}
.bf-topbar__brand:hover { color: var(--bf-text); }

/*
 * The mark returns on a wide screen — but only when it is the whole of
 * the brand. Where the rail is open it carries the name already, so the
 * mark beside it would be a second answer to the same question.
 */
@media (min-width: 861px) {
  .bf-topbar__brand--narrow { display: none; }
}

/* ---- Model picker ---- */

.bf-picker { position: relative; }

.bf-picker__btn {
  display: flex;
  align-items: center;
  gap: 10px;
  /*
   * The same control the picture page has.
   *
   * This was a pill outlined in the model's own colour — a different
   * shape, a different border and a different height from the menu on
   * every other page, so choosing a model looked like a different
   * feature depending on where you stood.
   */
  height: 46px;
  padding: 0 13px;
  border: 1px solid var(--border-default);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(255,255,255,.018), rgba(255,255,255,0)), var(--surface-2);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: var(--bf-ease-all);
  /*
   * No ring behind the control.
   *
   * This drew a 3px halo in `--model-accent`, which the markup used to set
   * inline from whichever model was loaded. That inline value is gone now,
   * so the halo fell back to the site's own colour and every picker wore
   * an orange ring — on the button and again under the pointer, because
   * the shadow sits on the resting rule and hover never cleared it.
   */
  box-shadow: none;
}
.bf-picker__btn:hover {
  border-color: var(--border-strong);
  background: linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,0)), var(--surface-3);
}

.bf-picker.is-open .bf-picker__btn { border-color: var(--border-strong); box-shadow: none; }

.bf-picker__btn .bf-model-logo {
  width: 26px;
  height: 26px;
  border-radius: 8px;
  font-size: var(--bf-size-2xs);
  /*
   * A plain tile in the control, with no colour behind the mark.
   *
   * The tile tints itself with `--logo-accent`, which the markup used to
   * set inline from whichever model was loaded. That inline value is gone,
   * so the tint fell back to the site's own colour and every picker had an
   * orange wash behind its logo. Here the tile is just a surface; on the
   * models page, where the marks are being compared, the tint still means
   * something.
   */
  background: var(--surface-3);
  border: 1px solid var(--border-default);
  color: var(--text-secondary);
  overflow: hidden;
  box-sizing: border-box;
}
/* A mark this small needs a touch more room inside its tile, or it reads
   as a solid block of colour rather than a shape. */
/*
 * The mark sits inside its tile, with room around it.
 *
 * The shared rule gives an inline SVG 74% of the tile, which on a 26px
 * tile leaves about three pixels a side — and a mark whose artwork
 * reaches the edge of its own viewBox, like a starburst, then touches the
 * rounded border and reads as overflowing it.
 *
 * Both forms are sized here so a stored image and an inline mark sit the
 * same, rather than one being padded and the other not.
 */
.bf-picker__btn .bf-model-logo img,
.bf-picker__btn .bf-model-logo svg {
  /*
   * Contained, and clipped by the tile.
   *
   * A percentage of a flex item is measured against the item's own
   * content box, which for a mark with no intrinsic size is not the tile
   * — so the mark could still spill past the rounded corner. Fixed pixels
   * against a fixed tile cannot, and `object-fit: contain` keeps a mark
   * that is not square from being stretched.
   */
  width: 16px;
  height: 16px;
  object-fit: contain;
}
.bf-picker__name { white-space: nowrap; }
.bf-picker__chev { color: var(--bf-text-dim); transition: transform var(--bf-fast) var(--bf-ease); }
.bf-picker.is-open .bf-picker__chev { transform: rotate(180deg); }

.bf-picker__panel {
  position: absolute;
  inset-block-start: calc(100% + 10px);
  inset-inline-start: 0;
  z-index: var(--bf-z-panel);
  /*
   * Smaller, and made of glass.
   *
   * The same treatment as the image page's picker, and for the same
   * reason: at 340 it read as a panel of the page rather than something
   * floating over it. The blur needs a genuinely translucent background
   * to do anything, so this one is translucent.
   */
  /*
   * The reference's own panel: 292, dark smoked glass.
   *
   * This was brown and two-thirds transparent, which let the page show
   * through enough to make the rows hard to read.
   */
  width: 292px;
  max-width: calc(100vw - 32px);
  padding: 8px;
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 14px;
  background:
    /*
     * Glass that stays black over an orange page.
     *
     * At .88 with saturate(115%), the copper behind the panel came
     * through the blur and the saturate lifted it — the menu read as
     * brown rather than black, measurably: 3–4 points of red over blue.
     * More opacity and no saturate brings it to 0 and keeps the blur,
     * which is what makes it glass in the first place.
     */
    linear-gradient(180deg, rgba(255,255,255,.018), rgba(255,255,255,0)),
    rgba(10,10,10,.95);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 24px 60px rgba(0,0,0,.52);
  max-height: calc(100vh - 130px);
  overflow-y: auto;
  scrollbar-width: thin;
  animation: bf-pop var(--bf-normal) var(--bf-ease-out);
}

/*
 * Measured from the reference: a 36px field on #161616, and 8px of air
 * beneath it before the filter pills.
 */
.bf-picker__search {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 36px;
  padding: 0 11px;
  margin-bottom: 8px;
  border-radius: 10px;
  background: #161616;
  border: 1px solid rgba(255,255,255,.07);
  border-radius: var(--bf-radius-sm);
  background: var(--bf-bg);
  color: var(--bf-text-faint);
}
.bf-picker__search input {
  flex: 1; min-width: 0; padding: 10px 0;
  border: 0; background: none; color: var(--bf-text);
  font-family: inherit; font-size: var(--bf-size-base);
}
.bf-picker__search input:focus { outline: none; }
.bf-picker__search input::-webkit-search-cancel-button { display: none; }

.bf-picker__list { max-height: 330px; overflow-y: auto; }

.bf-picker__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 52px;
  padding: 7px 9px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--text-primary);
  font-family: inherit;
  text-align: start;
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease),
              border-color var(--bf-fast) var(--bf-ease);
}
.bf-picker__item:hover { background: var(--bf-glass-strong); }
.bf-picker__item .bf-model-logo {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  font-size: var(--bf-size-2xs);
}

.bf-picker__meta {
  flex: 1;
  min-width: 0;
  display: grid;
  gap: 2px;
}
.bf-picker__meta strong {
  font-size: var(--bf-size-base); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/*
 * Overridden below, and left here on purpose.
 *
 * A second `.bf-picker__meta em` at the same specificity, further down the
 * file, wins every property it declares — including the rule that stops this
 * line wrapping. Declaring the wrap here as well looked like belt and braces
 * and was worse than either: with both in place, removing one changed
 * nothing, so the check that guards the row height could not be made to fail
 * and therefore proved nothing about it.
 *
 * One declaration, in the block that actually governs.
 */
.bf-picker__meta em { font-style: normal; font-size: var(--bf-size-xs); color: var(--bf-text-dim); }

/*
 * A small tag, the size the reference's are.
 *
 * As a pill at 11px it took as much room as the name beside it and set
 * the row's rhythm; a label should sit under the name, not next to it in
 * weight.
 */
/*
 * The tag never squeezes the name.
 *
 * At 120px of a 274px row the model's name was being cut to "... Banana
 * Pro" — the tag beside it was taking more room than the thing it
 * describes.
 */
.bf-picker__badge {
  flex: 0 1 auto;
  max-width: 64px;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 4px 7px;
  border-radius: 6px;
  background: rgba(169, 79, 49,.11);
  border: 1px solid rgba(169, 79, 49,.13);
  color: #B76B52;
  font-size: var(--bf-size-2xs);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
}

.bf-picker__tick { flex: none; color: var(--bf-accent); opacity: 0; }
.bf-picker__item.is-active .bf-picker__tick { opacity: 1; }

/* Unavailable models stay visible. A model that silently vanishes looks
   like a fault to the person who used it yesterday. */
.bf-picker__item.is-locked {
  opacity: .45;
  cursor: not-allowed;
}
.bf-picker__item.is-locked:hover { background: none; }
.bf-picker__lock { flex: none; color: var(--bf-text-dim); }

.bf-picker__empty { padding: 20px 12px; text-align: center; color: var(--bf-text-dim); font-size: var(--bf-size-sm); }

.bf-picker__all {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 6px;
  padding: 11px 12px;
  border-top: 1px solid var(--bf-line);
  border-radius: 0 0 var(--bf-radius-sm) var(--bf-radius-sm);
  color: var(--bf-text-muted);
  font-size: var(--bf-size-base);
}
/*
 * Brighter on hover, not orange.
 *
 * The accent already means "this is the model you are on" — the row
 * carries it, the tick carries it, the active filter carries it. A
 * footer link that borrows the same colour on hover claims to be a
 * selection when it is only a way out of the list.
 */
.bf-picker__all:hover {
  color: var(--text-primary);
  background: var(--bf-glass);
}

/* ---- Deep thinking toggle ---- */

.bf-think {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  cursor: pointer;
  user-select: none;
}
.bf-think input { position: absolute; opacity: 0; pointer-events: none; }

.bf-think__track {
  width: 44px; height: 25px;
  flex: none;
  padding: 3px;
  border-radius: var(--bf-radius-pill);
  background: var(--bf-surface-3);
  border: 1px solid var(--bf-line-strong);
  transition: background var(--bf-normal) var(--bf-ease), border-color var(--bf-normal) var(--bf-ease);
}
.bf-think__knob {
  display: block;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: var(--bf-text-dim);
  transition: transform var(--bf-normal) var(--bf-ease-out), background var(--bf-normal) var(--bf-ease);
}

.bf-think input:checked + .bf-think__track {
  background: var(--bf-accent);
  border-color: var(--bf-accent);
}
.bf-think input:checked + .bf-think__track .bf-think__knob {
  background: #fff;
  /* RTL: the knob travels toward the leading edge. */
  transform: translateX(-19px);
}

.bf-think__label { font-size: var(--bf-size-base); color: var(--bf-text-muted); white-space: nowrap; }
.bf-think input:checked ~ .bf-think__label { color: var(--bf-text); }

.bf-think input:disabled + .bf-think__track { opacity: .4; }
.bf-think:has(input:disabled) { cursor: not-allowed; opacity: .55; }

/* ---- Credit chip ---- */

.bf-credit {
  display: none;
  align-items: center;
  gap: 6px;
  margin-inline-start: auto;
  padding: 8px 16px;
  border: 1px solid var(--bf-accent-line);
  border-radius: var(--bf-radius-pill);
  background: var(--bf-accent-soft);
  font-size: var(--bf-size-sm);
  white-space: nowrap;
}
.bf-credit span { color: var(--bf-text-muted); }
.bf-credit strong { color: var(--bf-accent); font-weight: 700; }

@media (min-width: 720px) { .bf-credit { display: inline-flex; } }

.bf-more { position: relative; margin-inline-start: auto; }
@media (min-width: 720px) { .bf-more { margin-inline-start: 0; } }

/* ---------------------------------------------------------------------
 * Conversation
 * ------------------------------------------------------------------ */

/*
 * One column, one width.
 *
 * The thread ran the full width of the workspace while the composer
 * stopped at 820 — so a line of text and the box it was typed into did
 * not line up, and long answers ran wider than the eye tracks.
 *
 * 800 rather than the reference's 788: that shot is 1536 wide, and the
 * same proportion on a large monitor gives lines the eye loses the end
 * of. This holds at any screen.
 */
.bf-stream {
  min-width: 0;
  width: 100%;
  max-width: 800px;
  margin-inline: auto;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--bf-space-4) var(--bf-space-5);
  scroll-behavior: smooth;
}

/*
 * The empty state has to fit on one screen. A visitor who has not typed
 * anything yet should never have to scroll to see what they can do — the
 * suggestion cards are the only instructions on the page.
 */
.bf-stream:has(.bf-welcome:not(.is-hidden)) {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.bf-welcome {
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
  padding-block: clamp(12px, 3vh, 40px);
  text-align: center;
}
.bf-welcome.is-hidden { display: none; }

.bf-welcome h1 {
  font-size: clamp(22px, 3.4vh, 34px);
  margin-bottom: var(--bf-space-2);

  /*
   * Plain colour, not a gradient clipped to the text.
   *
   * The gradient needed `color: transparent`, which every child
   * inherited — so the accent word inside was invisible too. One word in
   * copper says the same thing and leaves the question readable.
   */
  color: var(--text-primary);
  animation-delay: 0ms;
  position: relative;
}

/*
 * Only the opening word takes the accent.
 *
 * The rest stays white so the question reads first — an entirely orange
 * line would make the loudest thing on an empty page a sentence nobody
 * needs to act on.
 */
.bf-welcome h1 b { color: var(--orange-500); font-weight: inherit; }
.bf-welcome__sub {
  color: var(--bf-text-muted);
  margin-bottom: 4px;
  animation-delay: 70ms;
}
.bf-welcome__sub strong { color: var(--bf-accent); font-weight: 500; }
.bf-welcome__hint {
  color: var(--bf-text-faint);
  font-size: var(--bf-size-sm);
  margin-bottom: clamp(16px, 4vh, 40px);
  animation-delay: 130ms;
}

.bf-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--bf-space-3);
}
@media (min-width: 760px) { .bf-cards { grid-template-columns: repeat(4, 1fr); } }

.bf-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--bf-space-2);
  padding: clamp(14px, 2.4vh, 22px) var(--bf-space-3);
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius);
  background: var(--bf-surface);
  color: var(--bf-text-muted);
  font-family: inherit;
  font-size: var(--bf-size-sm);
  line-height: 1.7;
  cursor: pointer;
  transition: border-color var(--bf-normal) var(--bf-ease),
              transform var(--bf-normal) var(--bf-ease-out),
              background var(--bf-normal) var(--bf-ease);
}
.bf-card:hover {
  transform: translateY(-3px);
  border-color: var(--bf-accent-line);
  background: var(--bf-surface-2);
  color: var(--bf-text);
}

/* The words on a suggestion card. Left unstyled, they inherited the
   card's centring and sat oddly against the icon. */
.bf-card__text {
  flex: 1;
  min-width: 0;
  text-align: start;
  line-height: 1.75;
}

.bf-card__icon { color: var(--bf-accent); }
.bf-card__icon--bulb  { color: #C98368; }
.bf-card__icon--code  { color: #7DB8FF; }
.bf-card__icon--image { color: #C08BFF; }

/* ---- Messages ---- */

.bf-messages {
  max-width: 780px;
  margin: 0 auto;
  padding-bottom: var(--bf-space-6);
  display: grid;
  gap: var(--bf-space-5);
}

.bf-msg { display: grid; gap: var(--bf-space-2); animation: bf-rise var(--bf-normal) var(--bf-ease-out); }

@keyframes bf-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.bf-msg--user {
  justify-items: start;
  position: relative;
}

/*
 * The reader's own words, in a box; the model's answer, on the page.
 *
 * Measured from the reference: #1C1C1C, with no border — the fill alone
 * separates it from a black page, and a line around it would be a
 * second boundary saying the same thing.
 */
.bf-msg--user .bf-msg__body {
  max-width: 82%;
  padding: 13px 18px;
  border-radius: 16px 16px 16px 6px;
  /* A step lighter than the page, so the person's own turn separates from
     the model's at a glance. Nothing on the model's side changed. */
  background: #212121;
  border: 0;
}

.bf-msg--ai .bf-msg__body {
  padding: 0;
  color: var(--bf-text);
}

.bf-msg__body {
  font-size: var(--bf-size-md);
  line-height: 2;

  /*
   * Newlines still show, but a real list is not pre-formatted text.
   *
   * The body kept `pre-wrap` because nothing turned markdown lists into
   * elements, so the raw dashes had to survive. Now that they become <ul>,
   * pre-wrap would add the source's line breaks on top of the list's own
   * layout and double every gap.
   */
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.bf-msg__body code {
  padding: 2px 6px;
  border-radius: 5px;
  background: var(--bf-surface-3);
  font-size: .92em;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.bf-msg__body pre {
  margin: var(--bf-space-3) 0;
  padding: 14px 16px;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-sm);
  background: #0C0C0C;
  overflow-x: auto;
  line-height: 1.75;
}
.bf-msg__body pre code { padding: 0; background: none; }

/* The reasoning trace, collapsed by default. */
.bf-think-block {
  margin-bottom: var(--bf-space-3);
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-sm);
  background: var(--bf-surface);
  overflow: hidden;
}
.bf-think-block summary {
  padding: 9px 14px;
  color: var(--bf-text-dim);
  font-size: var(--bf-size-sm);
  cursor: pointer;
  user-select: none;
}
.bf-think-block summary:hover { color: var(--bf-text-muted); }
.bf-think-block__body {
  padding: 0 14px 12px;
  color: var(--bf-text-dim);
  font-size: var(--bf-size-sm);
  line-height: 1.9;
  white-space: pre-wrap;
}

.bf-msg__foot {
  display: flex;
  align-items: center;
  gap: var(--bf-space-3);
  font-size: var(--bf-size-xs);
  color: var(--bf-text-faint);
}
.bf-msg__act {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border: 0;
  border-radius: var(--bf-radius-pill);
  background: none;
  color: var(--bf-text-faint);
  font-family: inherit;
  font-size: var(--bf-size-xs);
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease), color var(--bf-fast) var(--bf-ease);
}
.bf-msg__act:hover { background: var(--bf-glass-strong); color: var(--bf-text); }

.bf-msg__error {
  display: flex;
  align-items: flex-start;
  gap: var(--bf-space-2);
  padding: 12px 16px;
  border: 1px solid rgba(255,82,82,.3);
  border-radius: var(--bf-radius-sm);
  background: var(--bf-danger-soft);
  color: #FF9E9E;
  font-size: var(--bf-size-sm);
}

/*
 * The reference, when the message could not say more.
 *
 * Quiet on purpose: it is not part of the sentence, it is the thing to
 * quote when reporting it. `auto` on the start margin pushes it to the far
 * end of the box in both directions, so it reads as a label rather than as
 * a word in the middle of a Persian line, and `ltr` keeps `bf-a1b2c3d4e5`
 * from being reordered around its hyphen.
 */
.bf-msg__error-ref {
  margin-inline-start: auto;
  align-self: center;
  flex: none;
  direction: ltr;
  unicode-bidi: isolate;
  font-family: var(--bf-font-mono, ui-monospace, monospace);
  font-size: 11px;
  letter-spacing: .02em;
  color: rgba(255,158,158,.62);
  background: rgba(255,82,82,.10);
  border: 1px solid rgba(255,82,82,.18);
  border-radius: 5px;
  padding: 2px 7px;
  user-select: all;
  cursor: text;
}

/* Typing indicator, shown until the first token lands. */
.bf-typing { display: inline-flex; align-items: center; gap: 5px; padding: 6px 0; }
.bf-typing i {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--bf-accent);
  animation: bf-typing 1.3s var(--bf-ease) infinite;
}
.bf-typing i:nth-child(2) { animation-delay: .16s; }
.bf-typing i:nth-child(3) { animation-delay: .32s; }

@keyframes bf-typing {
  0%, 60%, 100% { opacity: .25; transform: translateY(0); }
  30%           { opacity: 1;   transform: translateY(-4px); }
}

/* ---------------------------------------------------------------------
 * Composer
 * ------------------------------------------------------------------ */

/*
 * The composer sits on the page.
 *
 * The reference gives it no surface of its own — measured #000000,
 * the same as the page behind it. What marks it is the field inside,
 * not a panel around it.
 */
.bf-composer {
  background: transparent;
  flex: none;
  padding: 0 var(--bf-space-5) var(--bf-space-4);
  max-width: 800px;
  width: 100%;
  margin-inline: auto;
  position: relative;
}

.bf-attach {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bf-space-2);
  margin-bottom: var(--bf-space-2);
}

/*
 * An attachment, visibly attached.
 *
 * It was a small pill with a filename in it — on a busy thread there
 * was no way to tell at a glance that a file had gone with the message,
 * which is the one thing an attachment has to say. A picture now shows
 * itself and anything else gets a mark, a name and a size.
 */
.bf-chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px 7px 8px;
  border: 1px solid var(--bf-line);
  border-radius: 12px;
  background: var(--bf-surface-2);
  font-size: var(--bf-size-sm);
  color: var(--bf-text-muted);
  max-width: 260px;
}

.bf-chip__thumb {
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: 8px;
  object-fit: cover;
  background: #0d0d0d;
}

.bf-chip__mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 9px;
  background: rgba(169, 79, 49,.09);
  color: var(--orange-500);
}

.bf-chip__body { display: grid; min-width: 0; line-height: 1.25; }

.bf-chip__name {
  color: var(--text-primary);
  font-size: 12.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bf-chip__body em { font-style: normal; font-size: 11px; color: var(--text-muted); }
.bf-chip button {
  display: flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; padding: 0;
  border: 0; border-radius: 50%;
  background: none; color: var(--bf-text-dim); cursor: pointer;
}
.bf-chip button:hover { background: var(--bf-glass-strong); color: var(--bf-text); }

.bf-input {
  display: flex;
  align-items: flex-end;
  gap: var(--bf-space-2);
  padding: 10px 12px;
  border: 1px solid var(--bf-line-strong);
  border-radius: var(--bf-radius);
  background: var(--bf-surface);
  transition: border-color var(--bf-fast) var(--bf-ease), box-shadow var(--bf-normal) var(--bf-ease);
}
/*
 * The same as every other field on the site: an accent border, no wash.
 *
 * This sheet loads after `base.css`, so a halo left here would win on
 * the workspaces and the fields would look different from one page to
 * the next.
 */
.bf-input:focus-within {
  border-color: var(--orange-500);
  box-shadow: none;
}

.bf-input__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px; height: 42px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--bf-glass);
  color: var(--bf-text-muted);
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease), color var(--bf-fast) var(--bf-ease);
}
.bf-input__btn:hover { background: var(--bf-glass-strong); color: var(--bf-text); }
.bf-input__btn.is-recording { background: var(--bf-danger-soft); color: var(--bf-danger); }

.bf-input textarea {
  flex: 1;
  min-width: 0;
  max-height: 210px;
  padding: 11px 6px;
  border: 0;
  background: none;
  color: var(--bf-text);
  font-family: inherit;
  font-size: var(--bf-size-md);
  line-height: 1.9;
  resize: none;
}
.bf-input textarea:focus { outline: none; }
.bf-input textarea::placeholder { color: var(--bf-text-faint); }

.bf-send {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--bf-surface-3);
  color: var(--bf-text-dim);
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease), color var(--bf-fast) var(--bf-ease);
}
/* Carries white text, so it takes the darker orange — the bright one
   measures 2.4:1 behind white and is hard work outdoors. */
.bf-send.is-ready { background: var(--bf-accent-solid); color: var(--bf-on-accent); }
.bf-send.is-ready:hover { background:
    linear-gradient(180deg, rgba(255,255,255,.18), rgba(255,255,255,0) 30%),
    linear-gradient(180deg, #B76B52 0%, #A94F31 50%, #A94F31 100%); box-shadow: var(--bf-accent-glow); }
.bf-send__stop { display: none; }

.bf-send.is-busy { background: var(--bf-surface-3); color: var(--bf-text); }
.bf-send.is-busy .bf-send__arrow { display: none; }
.bf-send.is-busy .bf-send__stop { display: block; }

.bf-disclaimer {
  margin: var(--bf-space-2) 0 0;
  text-align: center;
  font-size: var(--bf-size-xs);
  color: var(--bf-text-faint);
}

/* ---------------------------------------------------------------------
 * Toasts
 * ------------------------------------------------------------------ */

.bf-toasts {
  position: fixed;
  inset-block-start: var(--bf-space-5);
  inset-inline-start: var(--bf-space-5);
  z-index: var(--bf-z-toast);
  display: grid;
  gap: var(--bf-space-2);
  width: 300px;
  max-width: calc(100vw - 32px);
  pointer-events: none;
}

.bf-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--bf-space-2);
  padding: 13px 15px;
  border: 1px solid var(--bf-line-strong);
  border-radius: var(--bf-radius-md);
  background: var(--bf-surface-2);
  box-shadow: var(--bf-shadow);
  font-size: var(--bf-size-sm);
  pointer-events: auto;
  animation: bf-toast-in var(--bf-normal) var(--bf-ease-out);
}
.bf-toast.is-leaving { animation: bf-toast-out var(--bf-normal) var(--bf-ease) forwards; }

@keyframes bf-toast-in  { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: none; } }
@keyframes bf-toast-out { to   { opacity: 0; transform: translateX(-14px); } }

.bf-toast--warn    { border-color: rgba(255,176,32,.4); color: #C98368; }
.bf-toast--error   { border-color: rgba(255,82,82,.4);  color: #FF9E9E; }
.bf-toast--info    { border-color: rgba(77,163,255,.4); color: #9FCBFF; }
.bf-toast--success { border-color: rgba(52,208,127,.4); color: #7BE8B4; }

.bf-toast__body { flex: 1; min-width: 0; line-height: 1.8; }
.bf-toast__cta {
  display: inline-block;
  margin-top: 8px;
  padding: 6px 14px;
  border: 1px solid currentColor;
  border-radius: var(--bf-radius-pill);
  color: inherit;
  font-size: var(--bf-size-xs);
}
.bf-toast__close {
  flex: none; width: 20px; height: 20px; padding: 0;
  border: 0; background: none; color: inherit; cursor: pointer; opacity: .6;
}
.bf-toast__close:hover { opacity: 1; }

/* ---------------------------------------------------------------------
 * Modal
 * ------------------------------------------------------------------ */

.bf-modal {
  position: fixed;
  inset: 0;
  z-index: var(--bf-z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--bf-space-5);
  background: rgba(0,0,0,.66);
  backdrop-filter: blur(4px);
  animation: bf-fade var(--bf-fast) var(--bf-ease);
}
@keyframes bf-fade { from { opacity: 0; } to { opacity: 1; } }

.bf-modal__box {
  width: 100%;
  max-width: 400px;
  padding: var(--bf-space-6);
  border: 1px solid var(--bf-line-strong);
  border-radius: var(--bf-radius);
  background: var(--bf-surface);
  box-shadow: var(--bf-shadow-lg);
  animation: bf-pop var(--bf-normal) var(--bf-ease-out);
}
.bf-modal__box h2 { font-size: var(--bf-size-xl); margin-bottom: var(--bf-space-3); }
.bf-modal__box p { color: var(--bf-text-muted); font-size: var(--bf-size-base); }

.bf-modal__actions { display: flex; gap: var(--bf-space-3); margin-top: var(--bf-space-6); }
.bf-modal__actions .bf-btn { flex: 1; }

.bf-btn--danger { background: var(--bf-danger); color: #fff; font-weight: 700; }
.bf-btn--danger:hover { background: #FF6B6B; }

/* ---------------------------------------------------------------------
 * Narrow screens — the rail becomes an overlay
 * ------------------------------------------------------------------ */

@media (max-width: 860px) {
  .bf-app { grid-template-columns: 1fr; }

  /*
   * On a phone the rail is either absent or present. Nothing in between.
   *
   * Two previous attempts slid it off-screen with a transform, and both
   * times it ended up sitting on top of the conversation instead. The
   * reasoning was sound each time and wrong each time, because logical
   * properties flip with direction while `transform` does not, and getting
   * that pairing right is easy to believe and hard to verify without a
   * browser.
   *
   * `display: none` cannot be misread. It removes the element regardless of
   * direction, positioning, specificity or which edge anyone meant. The
   * slide is gone; a menu that works is worth more than one that animates.
   *
   * Physical properties throughout for the same reason: `right` means right.
   */
  .bf-rail {
    display: none;
  }

  .bf-app.rail-open .bf-rail {
    display: flex;
    position: fixed;
    top: 0;
    bottom: 0;
    right: 0;
    left: auto;
    width: min(86vw, 300px);
    max-width: 300px;
    z-index: var(--bf-z-rail);
    box-shadow: -8px 0 32px rgba(0, 0, 0, .5);
    animation: bf-rail-in 220ms var(--bf-ease-out);
  }

  /* Kept here too: the admin toolbar rule outside this block has higher
     specificity than a bare .bf-rail, but not than this. */
  .admin-bar .bf-app.rail-open .bf-rail {
    top: var(--bf-admin-bar, 0px);
  }

  @keyframes bf-rail-in {
    from { transform: translateX(100%); }
    to   { transform: none; }
  }

  /* Closing by tapping the conversation is what everyone tries first. */
  .bf-rail-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    z-index: var(--bf-z-backdrop);
    background: rgba(0, 0, 0, .55);
  }

  .bf-app.rail-open .bf-rail-backdrop { display: block; }

  .bf-main { grid-column: 1; grid-row: 1; }
  .bf-topbar__rail { display: inline-flex; }
  .bf-topbar { gap: var(--bf-space-2); padding-inline: var(--bf-space-4); }
  /*
   * The label stays.
   *
   * Hiding it saved about fifty pixels and cost the control its meaning: an
   * unlabelled switch is either ignored or flipped without knowing what
   * changed. Both are worse than a slightly tighter bar.
   *
   * Room is made by shrinking the type and letting the model name truncate,
   * which loses nothing — the full name is one tap away in the picker.
   */
  .bf-think__label {
    font-size: var(--bf-size-xs);
    white-space: nowrap;
  }

  .bf-think { gap: 6px; }

  .bf-think__track { width: 38px; height: 22px; }
  .bf-think__knob { width: 15px; height: 15px; }
  .bf-think input:checked + .bf-think__track .bf-think__knob {
    transform: translateX(-16px);
  }
  .bf-stream, .bf-composer { padding-inline: var(--bf-space-4); }

  .bf-toasts { inset-inline: var(--bf-space-4); width: auto; }
}


/* =====================================================================
 * Phones
 * ================================================================== */

@media (max-width: 640px) {

  /* The composer is the last thing above the gesture bar; without this it
     sits underneath it and the send button is unreachable. */
  .bf-composer {
    padding-bottom: max(var(--bf-space-4), env(safe-area-inset-bottom));
  }

  .bf-topbar {
    gap: 6px;
    padding: var(--bf-space-2) var(--bf-space-3);
  }

  /* Only the essentials survive on a narrow bar: model, thinking, menu. */
  .bf-topbar__brand { display: none; }
  .bf-picker__btn { padding: 7px 12px 7px 8px; font-size: var(--bf-size-base); }
  .bf-picker__btn .bf-model-logo { width: 22px; height: 22px; }
  .bf-picker__name {
    max-width: 22vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .bf-picker__panel {
    position: fixed;
    inset-block-start: auto;
    inset-block-end: 0;
    inset-inline: 0;
    width: auto;
    max-width: none;
    max-height: 70vh;
    overflow-y: auto;
    border-radius: var(--bf-radius) var(--bf-radius) 0 0;
    padding-bottom: max(8px, env(safe-area-inset-bottom));
  }

  .bf-welcome h1 { font-size: 22px; }
  .bf-welcome__hint { margin-bottom: var(--bf-space-5); }

  /* Four suggestion cards in one row is unreadable; two is fine. */
  .bf-cards { grid-template-columns: repeat(2, 1fr); gap: var(--bf-space-2); }
  .bf-card { padding: var(--bf-space-4) var(--bf-space-2); font-size: var(--bf-size-xs); }

  .bf-msg--user .bf-msg__body { max-width: 92%; }
  .bf-msg__body { font-size: var(--bf-size-base); }

  .bf-stream { padding-inline: var(--bf-space-3); }
  .bf-composer { padding-inline: var(--bf-space-3); }

  .bf-input { padding: 8px; gap: 6px; }
  .bf-input__btn { width: 38px; height: 38px; }
  .bf-send { width: 40px; height: 40px; }

  .bf-modal__box { padding: var(--bf-space-5); }
  .bf-modal__actions { flex-direction: column-reverse; }
}

/* Tablets: the rail stays visible but takes less of the screen. */
@media (min-width: 861px) and (max-width: 1100px) {
  :root { --bf-sidebar-w: 250px; }
}


/* The download sits with the other message actions but earns emphasis:
   it is the only one that produces something the person keeps. */
.bf-msg__act--zip {
  border: 1px solid var(--bf-accent-line);
  background: var(--bf-accent-soft);
  color: var(--bf-accent);
  font-weight: 500;
}
.bf-msg__act--zip:hover { background: rgba(169, 79, 49, .18); color: var(--bf-accent); }
.bf-msg__act--zip[disabled] { opacity: .6; cursor: wait; }


/* The archive announced below the reply, so a project's worth of code does
   not have to be scrolled past before the download is discovered. */
.bf-files-bar {
  display: flex;
  align-items: center;
  gap: var(--bf-space-2);
  margin-bottom: var(--bf-space-3);
  padding: 10px 14px;
  border: 1px solid var(--bf-accent-line);
  border-radius: var(--bf-radius-md);
  background: var(--bf-accent-soft);
  color: var(--bf-accent);
  font-size: var(--bf-size-sm);
}

.bf-files-bar span { flex: 1; min-width: 0; }

.bf-files-bar__btn {
  flex: none;
  padding: 7px 16px;
  border: 0;
  border-radius: var(--bf-radius-pill);
  background:
    /*
     * Centred on #A94F31, the orange of the greeting.
     *
     * The old stops ran #B76B52 to #A94F31 and the white sheen on top
     * lifted the crown to #B76B52 — light enough that the button and the
     * word "سلام" read as two different oranges. The gradient is kept,
     * because a flat fill is what makes a button look ordinary, but it
     * is now a shallow one around the true colour rather than a journey
     * away from it.
     */
    linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0) 34%),
    linear-gradient(180deg, #A94F31 0%, #A94F31 52%, #8B4128 100%);
  border: 1px solid rgba(183, 107, 82,.58);
  box-shadow:
    0 10px 26px rgba(169, 79, 49,.23),
    0 2px 5px rgba(169, 79, 49,.13),
    inset 0 1px 0 rgba(255,255,255,.33),
    inset 0 -1px 0 rgba(110,30,0,.25);
  color: #C98368;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.20),
    inset 0 -1px 0 rgba(0, 0, 0, 0.24),
    0 8px 25px rgba(169, 79, 49, 0.15),
    0 0 18px rgba(169, 79, 49, 0.10);
  font-family: inherit;
  font-size: var(--bf-size-xs);
  font-weight: 700;
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease);
}
.bf-files-bar__btn:hover { background:
    linear-gradient(180deg, rgba(255,255,255,.18), rgba(255,255,255,0) 30%),
    linear-gradient(180deg, #B76B52 0%, #A94F31 50%, #A94F31 100%); }
.bf-files-bar__btn[disabled] { opacity: .6; cursor: wait; }


/* =====================================================================
 * Processing stage
 *
 * A fixed-height strip above the reply. Fixed height matters: stages
 * change every few seconds, and a strip that grows or shrinks would shove
 * the conversation around while someone is reading it.
 * ================================================================== */

.bf-stage {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 34px;
  margin-bottom: var(--bf-space-2);
  padding: 0 13px;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-pill);
  background: var(--bf-surface);
  font-size: var(--bf-size-sm);
  color: var(--bf-text-muted);
  width: fit-content;
  max-width: 100%;
  transition: border-color var(--bf-normal) var(--bf-ease),
              color var(--bf-normal) var(--bf-ease),
              opacity var(--bf-slow) var(--bf-ease);
}

.bf-stage__icon {
  display: flex;
  flex: none;
  width: 16px;
  height: 16px;
}
.bf-stage__icon svg { width: 100%; height: 100%; }

.bf-stage__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The elapsed count is a detail, not the message. */
.bf-stage__time {
  flex: none;
  padding-inline-start: 8px;
  margin-inline-start: 2px;
  border-inline-start: 1px solid var(--bf-line);
  color: var(--bf-text-faint);
  font-size: var(--bf-size-xs);
  font-variant-numeric: tabular-nums;
}

/* ---- Tone ------------------------------------------------------------
 * Never colour alone: the icon and the wording carry the meaning too, so
 * the strip still reads correctly without colour vision.
 */

.bf-stage[data-tone="work"] {
  border-color: var(--bf-accent-line);
  color: var(--bf-accent);
}

.bf-stage[data-tone="done"] {
  border-color: rgba(52, 208, 127, .4);
  color: var(--bf-ok, #34D07F);
}

.bf-stage[data-tone="error"] {
  border-color: rgba(255, 82, 82, .4);
  color: #FF9E9E;
}

/* ---- Motion ---------------------------------------------------------
 * One slow pulse on the icon while work is happening. Deliberately not a
 * spinner: a spinner at every stage becomes noise, and a page full of
 * animation costs battery on the phones most people read this on.
 */

.bf-stage[data-tone="work"] .bf-stage__icon {
  animation: bf-stage-pulse 2s var(--bf-ease) infinite;
}

@keyframes bf-stage-pulse {
  0%, 100% { opacity: .5; }
  50%      { opacity: 1; }
}

/* Thinking is the one stage that may run for many minutes, so it gets a
   slightly livelier sign of life — a gentle breath rather than a spin,
   which would read as "stuck" at that duration. */
.bf-stage[data-stage="thinking"] .bf-stage__icon {
  animation: bf-stage-breathe 1.8s var(--bf-ease) infinite;
}

@keyframes bf-stage-breathe {
  0%, 100% { opacity: .45; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.12); }
}

/* Once the reply is there, the strip has nothing left to say. */
.bf-stage.is-retiring { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .bf-stage__icon { animation: none !important; }
}

@media (max-width: 640px) {
  .bf-stage { height: 30px; padding: 0 11px; font-size: var(--bf-size-xs); }
  .bf-stage__icon { width: 14px; height: 14px; }
}

/* =====================================================================
 * Very narrow phones (iPhone SE and similar, 320px)
 *
 * The top bar fits every common width except this one, where it runs over
 * by about twenty-four pixels. Nothing here is removed — a control without
 * its label is the problem this is solving — so the model name gives up the
 * space instead. Its full form is one tap away in the picker.
 * ================================================================== */

@media (max-width: 340px) {

  .bf-topbar {
    gap: 4px;
    padding-inline: 8px;
  }

  .bf-picker__name { max-width: 15vw; }
  .bf-picker__btn { padding: 7px 8px 7px 6px; }

  .bf-think__label { font-size: var(--bf-size-2xs); }
  .bf-think__track { width: 34px; height: 20px; }
  .bf-think__knob { width: 13px; height: 13px; }
  .bf-think input:checked + .bf-think__track .bf-think__knob {
    transform: translateX(-14px);
  }

  .bf-icon-btn { width: 34px; height: 34px; }
}

/* =====================================================================
 * Attachments
 * ================================================================== */


/* Shown only while a file is over the composer. */
.bf-drop {
  position: absolute;
  inset: 0;
  z-index: var(--bf-z-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px dashed var(--bf-accent);
  border-radius: var(--bf-radius);
  background: rgba(169, 79, 49, .12);
  backdrop-filter: blur(2px);
  color: var(--bf-accent);
  font-size: var(--bf-size-md);
  font-weight: 500;
  pointer-events: none;
}

.bf-chip em {
  font-style: normal;
  color: var(--bf-text-faint);
  font-size: var(--bf-size-xs);
}

/* A colour per kind, plus a shape — colour alone is not a label. */
.bf-chip--image  { border-color: rgba(192, 139, 255, .4); }
.bf-chip--document { border-color: rgba(125, 184, 255, .4); }
.bf-chip--archive {
  border-color: var(--bf-accent-line);
  background: var(--bf-accent-soft);
}
.bf-chip--archive .bf-chip__name { color: var(--bf-accent); }

/* An upload in progress is visibly not finished, and cannot be removed
   mid-flight — the request would complete and orphan the file. */
.bf-chip.is-uploading {
  opacity: .9;
  position: relative;
  /* Room along the bottom for the bar, so it never crowds the name. */
  padding-bottom: 12px;
}

/*
 * HOW FAR IT GOT, AS A SHAPE AND AS A NUMBER.
 *
 * The card used to breathe in and out while an upload ran, which says
 * "working" and nothing else: a slow upload and a stuck one look identical
 * for as long as anyone is willing to watch. A bar answers the question
 * being asked, and it replaces the animation rather than joining it.
 *
 * The bar sits along the bottom edge of the card, so a long filename never
 * pushes it out of the row.
 */
.bf-chip__bar {
  position: absolute;
  inset-inline: 10px;
  bottom: 6px;
  height: 3px;
  border-radius: 999px;
  background: var(--bf-glass-strong);
  overflow: hidden;
}

.bf-chip__bar i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--bf-accent);
  transition: width .18s var(--bf-ease);
}

/* The percentage takes the place the size will have once there is one. */
.bf-chip__pct {
  font-variant-numeric: tabular-nums;
  color: var(--bf-accent);
}

/*
 * A send button with nothing it may send yet.
 *
 * Distinct from `is-ready` being absent: this one is waiting on something
 * that is happening, rather than on the person typing.
 */
#bf-send:disabled,
#bf-send.is-waiting {
  opacity: .45;
  cursor: progress;
}

@keyframes bf-breathe-chip {
  0%, 100% { opacity: .45; }
  50%      { opacity: .8; }
}

@media (prefers-reduced-motion: reduce) {
  .bf-chip.is-uploading { animation: none; }
}

@media (max-width: 640px) {
  .bf-chip__name { max-width: 120px; }
  .bf-drop { font-size: var(--bf-size-sm); }
}

/* =====================================================================
 * Code blocks
 * ================================================================== */

.bf-code {
  margin: var(--bf-space-3) 0;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-md);
  overflow: hidden;
  background: var(--bf-surface-2, #161616);
}

.bf-code__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--bf-space-2);
  padding: 7px 12px;
  border-bottom: 1px solid var(--bf-line);
  background: var(--bf-surface);
}

.bf-code__lang {
  /* The token is --bf-font-mono; the shorter name never existed, so this
     declaration was dropped and the language label rendered in the
     Persian face like ordinary prose. */
  font-family: var(--bf-font-mono);
  font-size: var(--bf-size-xs);
  color: var(--bf-text-faint);
  direction: ltr;
  unicode-bidi: isolate;
}

.bf-code__copy {
  flex: none;
  padding: 4px 12px;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-pill);
  background: transparent;
  color: var(--bf-text-muted);
  font-family: inherit;
  font-size: var(--bf-size-xs);
  cursor: pointer;
  transition: color var(--bf-fast) var(--bf-ease),
              border-color var(--bf-fast) var(--bf-ease);
}
.bf-code__copy:hover { color: var(--bf-text); border-color: var(--bf-line-strong, #333); }
.bf-code__copy.is-done { color: var(--bf-ok, #34D07F); border-color: rgba(52, 208, 127, .4); }

.bf-code pre {
  margin: 0;
  padding: var(--bf-space-4);
  overflow-x: auto;
  direction: ltr;
  text-align: left;
}

/* ---- Highlighting -----------------------------------------------------
 * Four token classes, which is all a reader needs to find their way
 * through a block at a glance. Every colour also differs in weight, so
 * the code stays readable without colour vision.
 */

.hl-str { color: #A5D6A7; }
.hl-com { color: #6B7280; font-style: italic; }
.hl-kw  { color: #C98368; font-weight: 600; }
.hl-num { color: #90CAF9; }
.hl-var { color: #CE93D8; }

/* =====================================================================
 * Jump to the newest message
 *
 * Appears only when the reader has scrolled away, which is the only time
 * it means anything.
 * ================================================================== */

.bf-jump {
  position: absolute;
  inset-inline-end: var(--bf-space-6);
  bottom: 104px;
  z-index: var(--bf-z-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--bf-line);
  border-radius: 50%;
  background: var(--bf-surface);
  color: var(--bf-text-muted);
  cursor: pointer;
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity var(--bf-normal) var(--bf-ease),
              transform var(--bf-normal) var(--bf-ease);
}

.bf-jump.is-shown {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.bf-jump:hover { color: var(--bf-text); border-color: var(--bf-accent-line); }

/* =====================================================================
 * Editing your own message
 * ================================================================== */


/* Hidden until the message is hovered or focused, so a conversation is
   not covered in controls while being read. */
/*
 * Your own message's controls, beneath it.
 *
 * The pencil used to sit 34px outside the bubble, which is fine until
 * the bubble reaches the edge of the column — then half of it slid
 * under the rail and could not be pressed.
 *
 * Below the message there is always room, and it is where the model's
 * own actions already are, so both sides of the thread read the same.
 */
.bf-msg__acts {
  display: flex;
  gap: 2px;
  justify-content: flex-start;
  margin-top: 5px;
  opacity: 0;
  transition: opacity var(--bf-fast) var(--bf-ease);
}

/* A bare icon, unlike the model's own labelled pills above. */
.bf-msg__mine {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--bf-text-faint);
  cursor: pointer;
  transition: var(--bf-ease-all);
}

.bf-msg__mine:hover {
  color: var(--bf-text);
  background: var(--bf-glass);
}

/*
 * Shown on hover, but never hidden from a keyboard.
 *
 * `opacity: 0` leaves the buttons focusable, so tabbing to one brings
 * the row back — which is the only way to reach them without a mouse.
 */
.bf-msg--user:hover .bf-msg__acts,
.bf-msg__acts:focus-within { opacity: 1; }

/* Touch has no hover, so the row stays visible there. */
@media (hover: none) {
  .bf-msg__acts { opacity: 1; }
}

.bf-edit { margin-top: var(--bf-space-2); }

.bf-edit textarea {
  width: 100%;
  padding: var(--bf-space-3);
  border: 1px solid var(--bf-accent-line);
  border-radius: var(--bf-radius-md);
  background: var(--bf-surface);
  color: var(--bf-text);
  font-family: inherit;
  font-size: var(--bf-size-base);
  line-height: 1.8;
  resize: vertical;
}

.bf-edit__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--bf-space-2);
  margin-top: var(--bf-space-2);
}

.bf-edit__save,
.bf-edit__cancel {
  padding: 7px 16px;
  border-radius: var(--bf-radius-pill);
  font-family: inherit;
  font-size: var(--bf-size-xs);
  cursor: pointer;
}

.bf-edit__save {
  border: 0;
  background:
    /*
     * Centred on #A94F31, the orange of the greeting.
     *
     * The old stops ran #B76B52 to #A94F31 and the white sheen on top
     * lifted the crown to #B76B52 — light enough that the button and the
     * word "سلام" read as two different oranges. The gradient is kept,
     * because a flat fill is what makes a button look ordinary, but it
     * is now a shallow one around the true colour rather than a journey
     * away from it.
     */
    linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0) 34%),
    linear-gradient(180deg, #A94F31 0%, #A94F31 52%, #8B4128 100%);
  border: 1px solid rgba(183, 107, 82,.58);
  box-shadow:
    0 10px 26px rgba(169, 79, 49,.23),
    0 2px 5px rgba(169, 79, 49,.13),
    inset 0 1px 0 rgba(255,255,255,.33),
    inset 0 -1px 0 rgba(110,30,0,.25);
  color: #C98368;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.20),
    inset 0 -1px 0 rgba(0, 0, 0, 0.24),
    0 8px 25px rgba(169, 79, 49, 0.15),
    0 0 18px rgba(169, 79, 49, 0.10);
  font-weight: 600;
}
.bf-edit__save[disabled] { opacity: .6; cursor: wait; }

.bf-edit__cancel {
  border: 1px solid var(--bf-line);
  background: transparent;
  color: var(--bf-text-muted);
}

/* On a touchscreen there is no hover, so the control is always visible. */
@media (hover: none) {
  .bf-msg__edit {
    opacity: 1;
    position: static;
    margin-top: 4px;
    margin-inline-start: auto;
  }
}

@media (max-width: 640px) {
  .bf-jump { inset-inline-end: var(--bf-space-4); bottom: 96px; }
  .bf-code pre { padding: var(--bf-space-3); font-size: 12.5px; }
}

/* =====================================================================
 * Reasoning depth
 *
 * A segmented control rather than a dropdown: there are three to five
 * options, they are ordered, and seeing all of them at once is what makes
 * the trade-off legible.
 * ================================================================== */

.bf-effort {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
}

.bf-effort__label {
  font-size: var(--bf-size-xs);
  color: var(--bf-text-faint);
  white-space: nowrap;
}

.bf-effort__opts {
  display: flex;
  padding: 2px;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-pill);
  background: var(--bf-surface);
}

.bf-effort__opt {
  padding: 5px 11px;
  border: 0;
  border-radius: var(--bf-radius-pill);
  background: transparent;
  color: var(--bf-text-faint);
  font-family: inherit;
  font-size: var(--bf-size-xs);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--bf-fast) var(--bf-ease), color var(--bf-fast) var(--bf-ease);
}

.bf-effort__opt:hover { color: var(--bf-text-muted); }

.bf-effort__opt[aria-checked="true"] {
  background: var(--bf-accent-soft);
  color: var(--bf-accent);
  font-weight: 600;
}

/* =====================================================================
 * Search tools
 *
 * Pressed state carries weight and colour, not colour alone.
 * ================================================================== */

.bf-tool-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  padding: 6px 12px;
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-pill);
  background: transparent;
  color: var(--bf-text-faint);
  font-family: inherit;
  font-size: var(--bf-size-xs);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color var(--bf-fast) var(--bf-ease),
              color var(--bf-fast) var(--bf-ease),
              background var(--bf-fast) var(--bf-ease);
}

.bf-tool-btn:hover { color: var(--bf-text-muted); }

.bf-tool-btn[aria-pressed="true"] {
  border-color: var(--bf-accent-line);
  background: var(--bf-accent-soft);
  color: var(--bf-accent);
  font-weight: 600;
}

.bf-tool-btn[hidden] { display: none; }

/* On a narrow bar the labels go and the icons stay — a pressed icon still
   reads as on, where a missing control would not. */
@media (max-width: 860px) {
  .bf-tool-btn span { display: none; }
  .bf-tool-btn { padding: 6px 9px; }
  .bf-effort__label { display: none; }
  .bf-effort__opt { padding: 5px 9px; }
}

@media (max-width: 480px) {
  .bf-effort__opt { padding: 5px 7px; font-size: var(--bf-size-2xs); }
}

/* =====================================================================
 * The stepped path
 *
 * A checklist rather than a single label: the reader can see where the
 * request is in a process, not just what is happening this instant.
 * Height changes only when the list is collapsed at the end, so nothing
 * shifts under the eye while it is running.
 * ================================================================== */

.bf-steps {
  margin-bottom: var(--bf-space-3);
  border: 1px solid var(--bf-line);
  border-radius: var(--bf-radius-md);
  background: var(--bf-surface);
  overflow: hidden;
}

.bf-steps__head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 14px;
  font-size: var(--bf-size-sm);
  color: var(--bf-text-muted);
}

.bf-steps.is-collapsed .bf-steps__head { cursor: pointer; }

.bf-steps__dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--bf-accent);
  animation: bf-steps-pulse 1.6s var(--bf-ease) infinite;
}

.bf-steps__title { flex: 1; min-width: 0; }

.bf-steps__time {
  flex: none;
  color: var(--bf-text-faint);
  font-size: var(--bf-size-xs);
  font-variant-numeric: tabular-nums;
}

@keyframes bf-steps-pulse {
  0%, 100% { opacity: .35; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.25); }
}

.bf-steps__list {
  list-style: none;
  margin: 0;
  padding: 0 14px 12px;
}

.bf-steps.is-collapsed .bf-steps__list { display: none; }

.bf-steps.is-finished .bf-steps__dot {
  background: var(--bf-ok, #34D07F);
  animation: none;
}

.bf-steps__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 5px 0;
  color: var(--bf-text-faint);
  font-size: var(--bf-size-sm);
  transition: color var(--bf-normal) var(--bf-ease);
}

/* The line joining the marks, which is what makes it read as a sequence
   rather than a list of unrelated items. */
.bf-steps__item::before {
  content: '';
  position: absolute;
  inset-inline-start: 9px;
  top: -4px;
  width: 1px;
  height: 10px;
  background: var(--bf-line);
}

.bf-steps__item:first-child::before { display: none; }

.bf-steps__mark {
  flex: none;
  position: relative;
  width: 19px;
  height: 19px;
  border: 1.5px solid var(--bf-line);
  border-radius: 50%;
  transition: border-color var(--bf-normal) var(--bf-ease),
              background var(--bf-normal) var(--bf-ease);
}

/* Done: a tick, drawn rather than a font glyph so it never depends on
   what is installed. */
.bf-steps__item.is-done { color: var(--bf-text-muted); }

.bf-steps__item.is-done .bf-steps__mark {
  border-color: var(--bf-ok, #34D07F);
  background: var(--bf-ok, #34D07F);
}

.bf-steps__item.is-done .bf-steps__mark::after {
  content: '';
  position: absolute;
  inset-inline-start: 5px;
  top: 3px;
  width: 5px;
  height: 9px;
  border: solid #0B1F14;
  border-width: 0 1.8px 1.8px 0;
  transform: rotate(45deg);
}

/* Running: a filled centre with a ring, which reads as "here" at a glance. */
.bf-steps__item.is-active { color: var(--bf-accent); font-weight: 500; }

.bf-steps__item.is-active .bf-steps__mark {
  border-color: var(--bf-accent);
}

.bf-steps__item.is-active .bf-steps__mark::after {
  content: '';
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--bf-accent);
  animation: bf-steps-pulse 1.6s var(--bf-ease) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .bf-steps__dot,
  .bf-steps__item.is-active .bf-steps__mark::after { animation: none; }
}

@media (max-width: 640px) {
  .bf-steps__head { padding: 9px 12px; font-size: var(--bf-size-xs); }
  .bf-steps__list { padding: 0 12px 10px; }
  .bf-steps__item { font-size: var(--bf-size-xs); gap: 9px; }
  .bf-steps__mark { width: 17px; height: 17px; }
  .bf-steps__item.is-done .bf-steps__mark::after { inset-inline-start: 4.5px; top: 2.5px; }
}

/* A search that finds nothing should say so, not leave an empty column. */

.bf-thread[hidden],
.bf-rail__group[hidden] { display: none; }

/* =====================================================================
 * Nothing scrolls sideways. Ever.
 *
 * A reply arrived as one enormous fenced block — the model had wrapped a
 * whole prompt in code fences — and the page stretched to fit its widest
 * line. Reading it meant dragging horizontally across a screen and a half.
 *
 * Two separate faults, both needed fixing:
 *
 *   The block did not wrap. `overflow-x: auto` was supposed to keep the
 *   scrolling inside the block, and would have, except:
 *
 *   Nothing in the chain above it could shrink. A grid or flex child
 *   defaults to `min-width: auto`, which means "at least as wide as my
 *   content" — so a wide `pre` pushed its parent, which pushed the column,
 *   which pushed the page. `overflow-x: auto` never got the chance.
 *
 * Both are closed here, and the whole chain is pinned. Long lines wrap
 * rather than scroll: a horizontal scrollbar inside a code block is
 * tolerable on a desktop and miserable on a phone, and this is read on
 * phones.
 * ================================================================== */

/*
 * Nothing overflows its parent.
 *
 * `.bf-stream` is left out: it carries a reading width of its own and
 * this rule, coming later, was resetting it to the full workspace — so
 * the thread ran wider than the box it is typed into.
 */
.bf-main,
.bf-thread-inner,
.bf-msg,
.bf-msg__body {
  min-width: 0;
  max-width: 100%;
}


.bf-stream { overflow-x: hidden; }

/* Prose: break a URL or a long token rather than widening the column. */

/* Code: wrap, and keep the block inside its own bounds whatever happens. */
.bf-code,
.bf-code pre,
.bf-msg__body pre {
  max-width: 100%;
  min-width: 0;
  overflow-x: hidden;
}

.bf-code pre,
.bf-msg__body pre {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
  tab-size: 2;
}

.bf-code pre code,
.bf-msg__body pre code {
  display: block;
  max-width: 100%;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Inline code in a Persian sentence must not drag the line either. */

/* A wide table is the one thing that genuinely cannot wrap, so it scrolls
   inside its own box — never the page. */
.bf-msg__body table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
}

/* Last line of defence: whatever else appears in a reply, it stays inside. */
.bf-msg__body > * { max-width: 100%; }
.bf-msg__body img { height: auto; }

/* =====================================================================
 * The tools row, under the composer
 *
 * Moved down from the top bar. These settings change what happens to the
 * message being written, so they belong beside it — a person deciding how
 * deeply to think is doing that while composing, not while reading the
 * title bar.
 * ================================================================== */

.bf-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  max-width: var(--bf-stream-w, 760px);
  margin: var(--bf-space-2) auto 0;
  padding-inline: var(--bf-space-2);
}

/* Empty for a model with no options — no stray gap under the box. */
.bf-tools:empty { display: none; }

.bf-tools .bf-effort,
.bf-tools .bf-think { flex: none; }

/* Down here there is room for the label again. */
.bf-tools .bf-think__label,
.bf-tools .bf-effort__label { display: inline; }

@media (max-width: 640px) {
  .bf-tools {
    gap: 6px;
    padding-inline: var(--bf-space-3);
    /* One line that scrolls beats two lines that push the composer up
       and cost the conversation its last visible message. */
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .bf-tools::-webkit-scrollbar { display: none; }
  .bf-tools .bf-effort__label { display: none; }
}

/* =====================================================================
 * The model picker
 *
 * Rebuilt to the reference: a rounded tile for the mark, name over vendor,
 * a capability tag on the right, and the selected row outlined in the
 * accent with a filled check.
 *
 * The tile is the important part. Vendor marks are drawn for whatever
 * background their owner had in mind — several are solid white — so one
 * dropped straight onto a dark page glares. Each mark gets its own tile,
 * tinted with that vendor's colour, which makes every one of them read
 * correctly and keeps the column even because the tiles match even when
 * the marks inside do not.
 * ================================================================== */


.bf-picker__item:hover { background: var(--bf-surface-2, rgba(255, 255, 255, .04)); }

/* Selected: outlined and tinted, so it reads as chosen rather than merely
   hovered — the two states must never be confusable. */
/*
 * The chosen row: outlined and tinted, as the reference has it.
 *
 * A filled row competes with the trigger for being the selection, and on
 * dark glass the tint alone reads as a hover — so it takes both, gently.
 */
.bf-picker__item.is-active {
  border-color: rgba(169, 79, 49,.38);
  background: linear-gradient(90deg, rgba(169, 79, 49,.11), rgba(169, 79, 49,.035));
  box-shadow: inset 0 1px 0 rgba(183, 107, 82,.06);
}

/*
 * The mark, at the size the reference draws it.
 *
 * A 40px plate pushed the name into a third of the row; the reference
 * uses a bare 24px mark.
 */
.bf-picker__item .bf-model-logo {
  width: 24px;
  height: 24px;
  flex: none;

  /*
   * The mark alone, inside the menu.
   *
   * A tinted tile with a border is right on the models page, where the
   * logo is the subject. In a 52px row it turns every name into a badge
   * beside a coloured square — the reference simply shows the mark.
   */
  border: 0;
  border-radius: 0;
  background: none;
  overflow: visible;
}

.bf-picker__item .bf-model-logo img { width: 100%; height: 100%; }

/*
 * The chosen row's name stays white.
 *
 * Colouring it made the row's own accent compete with the border and the
 * tick, and on a narrow panel the eye read the colour before the word.
 */
.bf-picker__item.is-active .bf-picker__meta strong { color: var(--text-primary); }

/* A hairline between rows, as the reference has. */
.bf-picker__item + .bf-picker__item::before {
  content: "";
  position: absolute;
  top: -1px;
  inset-inline: 9px;
  height: 1px;
  background: rgba(255,255,255,.055);
}

.bf-picker__item.is-active::before,
.bf-picker__item.is-active + .bf-picker__item::before { display: none; }

/* ---- The mark ----
 *
 * Only the size is set here. The tile itself — its tint, its border, the
 * padding around the mark — lives on the base `.bf-model-logo` rule in
 * models.css, so the picker button, these rows, the model cards and the
 * model page all look the same. Restating it here is how one of them ends
 * up different after an edit.
 */


/* ---- Name and vendor ---- */


/*
 * The name at the reference's size, with room to be whole.
 *
 * It was 15px and bold in a 136px space, so "Nano Banana Pro" came out
 * as "...o Banana Pro" — a name cut short is worse than a small one, and
 * the reference uses 14 at medium weight, which fits.
 */
.bf-picker__meta strong {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.25;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * THE LINE UNDER THE NAME NEVER WRAPS.
 *
 * `strong` above it is clipped with an ellipsis and this was not, because
 * until options arrived it held one short word — the vendor. Given a second
 * thing to hold, a row with four options wrapped and grew from 52px to 63px:
 * one row in a list of four a different height from the rest.
 */
.bf-picker__meta em {
  font-style: normal;
  font-size: var(--bf-size-2xs);
  line-height: 1.2;
  color: var(--text-muted);

  /*
   * No `white-space` or `overflow` here.
   *
   * They were here, and each of the three children below has its own — so
   * deleting either one from this rule changed nothing at all, and the check
   * that guards the row height could not be made to fail. Two guards that
   * cover each other are one guard and one lie about how well it is tested.
   * The three children keep theirs; this rule keeps none.
   */

  /*
   * A row, so the three things on it can be given different shares.
   *
   * The vendor keeps its width, the count keeps its width, and the option
   * names take whatever is left and are clipped there. As one clipped
   * string the count was the tail and the tail is what gets cut — the row
   * read «کیفیت بالا، متعا…» and said nothing about the two models it was
   * counting.
   */
  display: flex;
  align-items: baseline;
  gap: 0;
  min-width: 0;
}

/*
 * AND THE OPTIONS ARE NOT THE VENDOR.
 *
 * Same size, same colour, one space between them: «Openai لونا، ترا، سول»
 * is four words with nothing to say where the vendor stops. A dot and a
 * lighter shade separate the two without taking another line.
 *
 * The dot is drawn here rather than typed into the markup, because the
 * markup is also what the search reads — a separator in the text would be
 * a character somebody has to type to find their model.
 */
/*
 * The vendor gives way first.
 *
 * It is on every row and it repeats; the option names are the thing this
 * line was added to show. Shrinking them at the same rate put «Black Forest
 * Labs» on the row whole and cut «کیفیت بالا، متعادل، اقتصادی» down to
 * «کیفیت با…» — the repeated word kept, the new one thrown away.
 */
.bf-picker__vendor {
  /*
   * Gives way with the names, and clipped at its own end when it does.
   *
   * WHAT THIS IS NOT, AND WHY
   *
   * Three attempts to settle the row here all wrecked one side or the
   * other: `flex-shrink: 8` cut the vendor to «B.» before the names gave up
   * anything; `min-width: 4.5em` is a floor, so a vendor NARROWER than it
   * was widened to it and the space came out of the names — «Openai» is
   * under four and a half characters, and that alone cut «سول، ترا، لونا»
   * to «سول، ترا،…»; and `min-width: min-content` with `white-space:
   * nowrap` means the whole string, so it read "never shrink" and the names
   * took the entire squeeze.
   *
   * No share of a line is right for both a fourteen-character option list
   * and a twenty-seven-character one. The length is what needed bounding,
   * and `BF_Model::option_parts()` bounds it. With that done this rule can
   * be the plain one.
   */
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;

  /*
   * Clipped at its own end, not at the line's.
   *
   * «Black Forest Labs» inside a right-to-left line was being cut from the
   * left: the row read «…st Labs», an ellipsis in front of the end of a
   * word. Taking the direction from the name's own first letter puts the
   * ellipsis where the name actually stops, and still reads correctly for a
   * vendor written in Persian.
   */
  unicode-bidi: plaintext;
}



.bf-picker__opts {
  color: var(--text-primary);
  opacity: .72;

  /* Gives way, but half as fast as the vendor beside it. */
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bf-picker__opts::before {
  content: '·';
  margin: 0 5px;
  opacity: .5;
}

/* And the count never gives way, because it is the part worth keeping. */
.bf-picker__more {
  flex: none;
  margin-inline-start: 5px;
  color: var(--text-primary);
  opacity: .72;
}

/* ---- Capability tag ---- */

.bf-picker__badges {
  flex: none;
  display: flex;
  gap: 5px;
}


/* A colour per kind, matching the reference, each with its own text
   colour so the tag reads without relying on the fill alone. */
/*
 * One grey ladder, not four colours.
 *
 * Every badge had a hue of its own — orange, violet, blue, green — so a
 * list of five models carried five signals and none of them meant
 * anything. Orange in particular clashed with the row it sat in, since
 * that colour already says "this one is chosen".
 *
 * The steps differ in lightness alone: a stronger model reads brighter,
 * not better.
 */
.bf-picker__badge--fast   { border-color: rgba(255,255,255,.07); color: #7A7A7A; }
.bf-picker__badge--coding { border-color: rgba(255,255,255,.12); color: #9A9A9A; }
.bf-picker__badge--vision { border-color: rgba(255,255,255,.12); color: #9A9A9A; }
.bf-picker__badge--smart  { border-color: rgba(255,255,255,.20); color: #D6D6D6; }

/* A tier, not a capability — cool, so it never competes with the accent. */
.bf-picker__badge--pro    { background: rgba(148,163,184,.14); color: #CBD5E1; border-color: rgba(148,163,184,.28); }

/* ---- The check on the selected row ---- */

.bf-picker__check {
  flex: none;
  display: none;
  align-items: center;
  justify-content: center;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  background:
    /*
     * Centred on #A94F31, the orange of the greeting.
     *
     * The old stops ran #B76B52 to #A94F31 and the white sheen on top
     * lifted the crown to #B76B52 — light enough that the button and the
     * word "سلام" read as two different oranges. The gradient is kept,
     * because a flat fill is what makes a button look ordinary, but it
     * is now a shallow one around the true colour rather than a journey
     * away from it.
     */
    linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0) 34%),
    linear-gradient(180deg, #A94F31 0%, #A94F31 52%, #8B4128 100%);
  border: 1px solid rgba(183, 107, 82,.58);
  box-shadow:
    0 10px 26px rgba(169, 79, 49,.23),
    0 2px 5px rgba(169, 79, 49,.13),
    inset 0 1px 0 rgba(255,255,255,.33),
    inset 0 -1px 0 rgba(110,30,0,.25);
  color: #C98368;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.20),
    inset 0 -1px 0 rgba(0, 0, 0, 0.24),
    0 8px 25px rgba(169, 79, 49, 0.15),
    0 0 18px rgba(169, 79, 49, 0.10);
}

.bf-picker__item.is-active .bf-picker__check { display: flex; }

/* ---- Unavailable ---- */

.bf-picker__item.is-locked:hover { background: transparent; }

@media (max-width: 640px) {
  .bf-picker__item { padding: 9px 10px; gap: 10px; }
  .bf-picker__item .bf-model-logo { width: 36px; height: 36px; border-radius: 11px; }
  .bf-picker__item .bf-model-logo img { width: 21px; height: 21px; }
  .bf-picker__meta strong { font-size: var(--bf-size-base); }
}

/* What was attached to a message, shown above it and kept there. */
.bf-msg__files {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
  justify-content: flex-end;
}

.bf-msg--user .bf-msg__files .bf-chip {
  background: var(--bf-surface);
  border-color: var(--bf-line);
}

/* =====================================================================
 * Reasoning depth, inside the composer
 *
 * A chip beside the send button that opens a short list. Placed in the box
 * because it changes what happens to the message being written, and
 * collapsed because five options laid flat would crowd the one thing the
 * box is for.
 * ================================================================== */

/* =====================================================================
 * Effort — the depth control
 *
 * The same values as the reference. Only the look changes here: every
 * class name, hook and data attribute is the one the script already
 * drives, so the five levels and what they send are untouched.
 * ================================================================== */

.bf-depth { position: relative; display: inline-flex; }

.bf-depth__btn {
  height: 42px;
  min-width: 122px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 13px;
  box-sizing: border-box;
  border-radius: 9px;
  border: 1px solid rgba(255,255,255,.09);
  outline: none;
  background: linear-gradient(180deg, rgba(255,255,255,.022), rgba(255,255,255,0)), #0a0a0a;
  color: #ececec;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.018);
  transition: border-color .16s ease, background .16s ease, color .16s ease;
}

.bf-depth__btn:hover {
  border-color: rgba(255,255,255,.15);
  background: linear-gradient(180deg, rgba(255,255,255,.032), transparent), #0d0d0d;
}

.bf-depth__btn[aria-expanded="true"] {
  border-color: rgba(169, 79, 49,.72);
  background: linear-gradient(180deg, rgba(169, 79, 49,.055), rgba(169, 79, 49,.014)), #0a0a0a;
}

.bf-depth__btn > svg { flex: none; color: rgba(255,255,255,.62); transition: color .16s ease; }
.bf-depth__btn[aria-expanded="true"] > svg { color: var(--orange-500); }

.bf-depth__btn:focus-visible {
  border-color: rgba(169, 79, 49,.75);
  box-shadow: 0 0 0 2px rgba(169, 79, 49,.10);
}

.bf-depth__btn:disabled {
  opacity: .42;
  cursor: not-allowed;
  color: rgba(255,255,255,.42);
  background: #070707;
  border-color: rgba(255,255,255,.05);
}

/*
 * The panel opens upward.
 *
 * The composer sits near the foot of the page, so downward would run
 * off the bottom of the screen.
 */
.bf-depth__menu {
  position: absolute;
  inset-inline-start: 0;
  bottom: calc(100% + 7px);
  z-index: var(--bf-z-menu);
  width: 286px;
  padding: 6px;
  box-sizing: border-box;
  border-radius: 12px;
  border: 1px solid rgba(255,255,255,.09);
  background:
    linear-gradient(180deg, rgba(255,255,255,.018), rgba(255,255,255,0) 35%),
    rgba(10,10,10,.95);
  /* No saturate: it pulls the page's copper through the blur. */
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow:
    0 18px 48px rgba(0,0,0,.58),
    0 5px 14px rgba(0,0,0,.24);
  transform-origin: bottom left;
}

.bf-depth__menu[hidden] { display: none; }

.bf-depth__title {
  margin: 4px 8px 6px;
  color: var(--text-muted);
  font-size: var(--bf-size-2xs);
}

.bf-depth__opt {
  position: relative;
  width: 100%;
  min-height: 63px;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 11px;
  box-sizing: border-box;
  border-radius: 9px;
  border: 1px solid transparent;
  background: transparent;
  color: #ededed;
  font-family: inherit;
  text-align: start;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}

.bf-depth__opt + .bf-depth__opt { margin-top: 2px; }
.bf-depth__opt:hover { background: rgba(255,255,255,.026); }

.bf-depth__opt strong { display: block; color: #f2f2f2; font-size: 13px; font-weight: 600; line-height: 1.35; }

.bf-depth__opt em {
  display: block;
  margin-top: 3px;
  font-style: normal;
  color: rgba(255,255,255,.46);
  font-size: var(--bf-size-2xs);
  font-weight: 400;
  line-height: 1.45;
}

.bf-depth__opt[aria-selected="true"] {
  border-color: rgba(169, 79, 49,.62);
  background:
    radial-gradient(circle at 82% 50%, rgba(169, 79, 49,.065), transparent 55%),
    linear-gradient(90deg, rgba(169, 79, 49,.09), rgba(169, 79, 49,.025));
}

/* The tick, drawn rather than shipped as another element. */
.bf-depth__opt[aria-selected="true"]::after {
  content: "";
  width: 17px;
  height: 17px;
  flex: none;
  background: currentColor;
  color: var(--orange-500);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>") center / contain no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>") center / contain no-repeat;
}

@media (max-width: 640px) {
  .bf-depth__btn { height: 40px; min-width: 104px; padding: 0 11px; gap: 7px; }
  .bf-depth__menu { width: min(286px, calc(100vw - 24px)); }
}


.bf-depth[hidden] { display: none; }


.bf-depth__btn svg { width: 16px; height: 16px; flex: none; }

.bf-depth__btn:hover { color: var(--bf-text-muted); border-color: var(--bf-line-strong, #333); }

.bf-depth__btn[aria-expanded="true"] {
  color: var(--bf-accent);
  border-color: var(--bf-accent-line);
  background: var(--bf-accent-soft);
}

/* Opens upward: the composer sits at the bottom of the screen, and a menu
   dropping down would go off it. */

.bf-depth__menu[hidden] { display: none; }

/*
 * Sizes here are a step up from the rest of the interface, on purpose.
 *
 * Persian sets smaller than Latin at the same pixel size — the dots and
 * marks that distinguish letters are the first thing to go — so 12px that
 * reads acceptably in English is genuinely hard work here. These are the
 * descriptions that make the choice comprehensible; setting them in type
 * nobody reads is the same as not writing them.
 */


.bf-depth__opt + .bf-depth__opt { margin-top: 2px; }

.bf-depth__opt:hover { background: rgba(255, 255, 255, .06); }

.bf-depth__opt strong {
  font-size: var(--bf-size-md);
  font-weight: 600;
  color: var(--bf-text);
  line-height: 1.6;
}

.bf-depth__opt em {
  font-style: normal;
  font-size: var(--bf-size-sm);
  color: var(--bf-text-muted);
  /* Persian needs more room between lines than Latin; at 1.7 the
     descenders and the marks above the next line start to collide. */
  line-height: 1.95;
}

/* Chosen: tinted and marked, so it reads as selected rather than hovered. */
.bf-depth__opt[aria-selected="true"] { background: var(--bf-accent-soft); }
.bf-depth__opt[aria-selected="true"] strong { color: var(--bf-accent); font-weight: 700; }
/* Lifted rather than dimmed on the chosen row — the description matters
   most on the option someone is about to keep. */
.bf-depth__opt[aria-selected="true"] em { color: var(--bf-text); }

/* The switch, when the model takes one instead. */
.bf-input .bf-think { flex: none; margin-inline-end: 2px; }
.bf-input .bf-think[hidden] { display: none; }

@media (max-width: 640px) {
  /* Still matched to the send button, which also shrinks here. */
  .bf-depth__btn { height: 38px; padding: 0 12px; font-size: var(--bf-size-sm); }

  /*
   * AND IT SIZES TO ITS LABEL RATHER THAN TO A NUMBER.
   *
   * `min-width: 104px` was set so one chip would not look mean beside the
   * send button. With two of them — a model that has both options and
   * graded reasoning — that is 208px reserved out of a 360px screen
   * before anything else is placed, and what is left is the box the
   * message goes in. «Sol» and «متعادل» need nothing like 104px.
   */
  .bf-depth__btn { min-width: 0; }

  /* Nearly the full width, because the descriptions are the point and a
     narrow menu would wrap every one of them to three lines. */
  .bf-depth__menu { width: min(84vw, 288px); }
  .bf-depth__opt strong { font-size: var(--bf-size-base); }
  .bf-depth__opt em { font-size: var(--bf-size-sm); }

  .bf-input .bf-think__label { display: none; }
}

/* =====================================================================
 * The picker button wears the model's own colour
 *
 * A green mark ringed in orange reads as a mistake rather than a theme.
 * The ring, the glow and the chevron all take `--model-accent`, which the
 * markup sets from the model and the script updates when it changes — so
 * choosing GPT turns the button green and choosing Claude turns it back.
 *
 * The accent is per-model and already editable where models are managed;
 * this is simply the second place it was not being used.
 * ================================================================== */



/*
 * Open, but not shouting.
 *
 * The ring in the model's own colour made an open menu the loudest thing
 * on the page; the reference simply firms the border.
 */
.bf-picker__btn[aria-expanded="true"] { border-color: var(--border-strong); box-shadow: none; }

.bf-picker__btn svg { color: var(--text-muted); }

/* Without color-mix the ring simply follows the site accent, which is
   never wrong — only less specific. */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
  .bf-picker__btn { border-color: var(--bf-line-strong); box-shadow: none; }
}

/* =====================================================================
 * A built archive
 *
 * Shown rather than silently downloaded. A button that drops a file into
 * the downloads folder gives no way to tell whether it holds what was
 * expected — you find out by unzipping it. The listing turns the archive
 * into something with a shape.
 * ================================================================== */

.bf-archive {
  margin-bottom: var(--bf-space-3);
  border: 1px solid var(--bf-accent-line);
  border-radius: var(--bf-radius-md);
  background: var(--bf-accent-soft);
  overflow: hidden;
}

.bf-archive__head {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  color: var(--bf-accent);
}

.bf-archive__head svg { flex: none; }

.bf-archive__meta { flex: 1; min-width: 0; display: grid; gap: 1px; }

.bf-archive__meta strong {
  font-size: var(--bf-size-base);
  font-weight: 600;
}

.bf-archive__meta em {
  font-style: normal;
  font-size: var(--bf-size-xs);
  color: var(--bf-text-faint);
}

.bf-archive__get {
  flex: none;
  padding: 8px 20px;
  border-radius: var(--bf-radius-pill);
  background:
    /*
     * Centred on #A94F31, the orange of the greeting.
     *
     * The old stops ran #B76B52 to #A94F31 and the white sheen on top
     * lifted the crown to #B76B52 — light enough that the button and the
     * word "سلام" read as two different oranges. The gradient is kept,
     * because a flat fill is what makes a button look ordinary, but it
     * is now a shallow one around the true colour rather than a journey
     * away from it.
     */
    linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0) 34%),
    linear-gradient(180deg, #A94F31 0%, #A94F31 52%, #8B4128 100%);
  border: 1px solid rgba(183, 107, 82,.58);
  box-shadow:
    0 10px 26px rgba(169, 79, 49,.23),
    0 2px 5px rgba(169, 79, 49,.13),
    inset 0 1px 0 rgba(255,255,255,.33),
    inset 0 -1px 0 rgba(110,30,0,.25);
  color: #C98368;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.20),
    inset 0 -1px 0 rgba(0, 0, 0, 0.24),
    0 8px 25px rgba(169, 79, 49, 0.15),
    0 0 18px rgba(169, 79, 49, 0.10);
  font-size: var(--bf-size-sm);
  font-weight: 600;
  text-decoration: none;
  transition: background var(--bf-fast) var(--bf-ease);
}

.bf-archive__get:hover { background:
    linear-gradient(180deg, rgba(255,255,255,.18), rgba(255,255,255,0) 30%),
    linear-gradient(180deg, #B76B52 0%, #A94F31 50%, #A94F31 100%); }

.bf-archive__list {
  list-style: none;
  margin: 0;
  padding: 0 14px 12px;
  max-height: 190px;
  overflow-y: auto;
}

.bf-archive__list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--bf-space-3);
  padding: 5px 0;
  border-top: 1px solid var(--bf-accent-line);
  font-size: var(--bf-size-sm);
  color: var(--bf-text-muted);
}

/* Paths are Latin and read left to right even in a Persian page. */
.bf-archive__list span {
  direction: ltr;
  unicode-bidi: isolate;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bf-archive__list em {
  flex: none;
  font-style: normal;
  color: var(--bf-text-faint);
  font-size: var(--bf-size-xs);
}

@media (max-width: 640px) {
  .bf-archive__head { padding: 10px 12px; gap: 9px; }
  .bf-archive__get { padding: 7px 15px; }
  .bf-archive__list { padding: 0 12px 10px; max-height: 150px; }
}

/* =====================================================================
 * The welcome arrives rather than appearing
 *
 * Everything on this screen landing at once has no order, and the eye has
 * to find where to start. Staggered, it reads the way it was written:
 * the question, then who is answering, then what you might ask.
 *
 * Sixty milliseconds apart. Enough to be a sequence, short enough that
 * nobody waits — a page that makes you watch it assemble is worse than
 * one that simply appears.
 *
 * This is entrance only. Nothing here delays a control becoming usable:
 * every element is clickable from the first frame, just faint.
 * ================================================================== */

.bf-welcome h1,
.bf-welcome__sub,
.bf-welcome__hint,
.bf-welcome .bf-card {
  animation: bf-arrive 420ms var(--bf-ease) both;
}

.bf-welcome .bf-card:nth-child(1) { animation-delay: 200ms; }
.bf-welcome .bf-card:nth-child(2) { animation-delay: 260ms; }
.bf-welcome .bf-card:nth-child(3) { animation-delay: 320ms; }
.bf-welcome .bf-card:nth-child(4) { animation-delay: 380ms; }

@keyframes bf-arrive {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}

/* The title is typed rather than faded, since it is a question being
   asked. The caret goes when the typing does. */

.bf-welcome h1.is-typing::after {
  content: '';
  display: inline-block;
  width: 2px;
  height: 0.95em;
  margin-inline-start: 3px;
  vertical-align: -2px;
  background: var(--bf-accent);
  animation: bf-caret 900ms steps(2, start) infinite;
}

@keyframes bf-caret { 50% { opacity: 0; } }

/*
 * Motion is a preference, and this is decoration.
 *
 * Anyone who asked their system for less of it gets the page whole and
 * still — losing nothing, since none of this carries information.
 */
@media (prefers-reduced-motion: reduce) {
  .bf-welcome h1,
  .bf-welcome__sub,
  .bf-welcome__hint,
  .bf-welcome .bf-card { animation: none; }

  .bf-welcome h1.is-typing::after { display: none; }
}

/* =====================================================================
 * Looking at a page before keeping it
 *
 * A built page arrived as a download: you saved it, found it, opened it,
 * and only then learned whether it was what you asked for. Here it draws
 * itself in place, inside a sandboxed frame — the page can render and
 * nothing else.
 * ================================================================== */

/*
 * Beside the conversation, not over it.
 *
 * Covering the whole screen hid the message that produced the page, so
 * you could not read the request and the result together. On a wide
 * screen it takes the right half and the thread keeps the rest; only a
 * narrow one gives it everything, where there is no room to share.
 */
.bf-preview {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(52vw, 760px);
  z-index: var(--bf-z-backdrop);
  display: grid;
  grid-template-rows: auto 1fr;
  padding: 16px;
  border-inline-start: 1px solid var(--border-strong);
  background: #060606;
  box-shadow: -30px 0 70px rgba(0,0,0,.55);
}

@media (max-width: 900px) {
  .bf-preview {
    inset: 0;
    width: auto;
    border-inline-start: 0;
    background: rgba(0,0,0,.72);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    padding: 12px;
  }
}

.bf-preview[hidden] { display: none !important; }

/*
 * THE PANEL BELOW THE ADMIN BAR.
 *
 * The owner is a site administrator, so WordPress draws its own 32-pixel
 * bar across the top of every page and the panel opened underneath it.
 * He said it did not matter because readers never see that bar — which is
 * true, and it is one rule, and he is the person who uses this most.
 */
body.admin-bar .bf-preview { inset-block-start: 32px; }

@media (max-width: 782px) {
  /* WordPress makes its own bar 46px below this width. */
  body.admin-bar .bf-preview { inset-block-start: 46px; }
}

/*
 * TWO VIEWS OF ONE FILE.
 *
 * The rendered page and the code that makes it, in one panel, because the
 * code used to live in the conversation — printed above the download and
 * folded behind a summary that still took a screen of room.
 */
.bf-preview__tabs {
  display: flex;
  gap: 2px;
  padding: 2px;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 9px;
  background: rgba(255, 255, 255, .03);
}

.bf-preview__tab {
  padding: 5px 12px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--bf-text-muted, #b5b5b5);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.bf-preview__tab:hover { color: #EDEDED; }

.bf-preview__tab.is-on {
  background: rgba(255, 255, 255, .09);
  color: #FFFFFF;
}

.bf-preview__tab[hidden] { display: none; }

/*
 * The code sits in the same row of the grid the frame does, so the two
 * swap in place rather than one pushing the other down.
 */
.bf-preview__code {
  position: relative;
  grid-row: 2;
  min-height: 0;
  overflow: auto;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 12px;
  background: #0E0E10;
}

.bf-preview__code[hidden] { display: none; }

.bf-preview__code pre {
  margin: 0;
  padding: 16px 18px;
  direction: ltr;
  text-align: left;
  font-family: var(--bf-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 12.5px;
  line-height: 1.75;
  white-space: pre;
  tab-size: 2;
}

/*
 * Pinned to the panel rather than to the text, so it stays reachable
 * while a long file is scrolled.
 */
.bf-preview__copy {
  position: sticky;
  inset-block-start: 10px;
  float: inline-end;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-block: 10px 0;
  margin-inline: 0 10px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 8px;
  background: rgba(20, 20, 22, .9);
  color: var(--bf-text-muted, #b5b5b5);
  cursor: pointer;
  z-index: 2;
}

.bf-preview__copy:hover { color: #EDEDED; border-color: rgba(255, 255, 255, .2); }

.bf-preview__copy.is-done { color: var(--bf-ok, #34D07F); }

.bf-preview__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin: 0 0 10px;
  padding: 0 2px;
}

.bf-preview__name {
  flex: 1;
  min-width: 0;
  color: var(--text-primary);
  font-size: 13.5px;
  font-weight: 600;
  direction: ltr;
  text-align: start;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bf-preview__open {
  flex: none;
  padding: 7px 12px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: rgba(255,255,255,.04);
  color: var(--text-secondary);
  font-size: 12.5px;
  transition: var(--bf-ease-all);
}

.bf-preview__open:hover { color: var(--text-primary); border-color: var(--orange-border); }

.bf-preview__shut {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: rgba(255,255,255,.04);
  color: var(--text-secondary);
  cursor: pointer;
  transition: var(--bf-ease-all);
}

.bf-preview__shut:hover { color: var(--text-primary); border-color: var(--orange-border); }

/*
 * White, because a page expects to be on white.
 *
 * Rendering someone's landing page on this site's black would show them
 * something that is not what they built.
 */
.bf-preview__frame {
  /* The same row the code view uses, so the two swap in place. */
  grid-row: 2;
  width: 100%;
  height: 100%;
  min-height: 0;
  margin: 0;
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 30px 70px rgba(0,0,0,.5);
}

.bf-preview__frame[hidden] { display: none; }

/* The button that opens it, beside the download. */
.bf-archive__look {
  flex: none;
  padding: 8px 14px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: rgba(255,255,255,.04);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: var(--bf-ease-all);
}

.bf-archive__look:hover { color: var(--text-primary); border-color: var(--orange-border); }

@media (max-width: 640px) {
  .bf-preview { padding: 12px; }
  .bf-preview__open { display: none; }
}

/*
 * Code, folded once it has become a file.
 *
 * Showing a whole page again beneath its own download makes the reader
 * scroll past a screen of markup to reach what they asked for. Kept,
 * but out of the way.
 */
/*
 * THE CODE LEAVES THE CONVERSATION ONCE IT IS A FILE.
 *
 * A delivered page used to be printed in the thread in full and then
 * folded behind a summary — which still left the fold, the language label
 * and a copy button between the answer and the download, and on a page of
 * any size the reader scrolled past all of it to reach the thing they had
 * asked for. The owner photographed exactly that: the code at the top, the
 * same code again lower down, and the download at the very bottom.
 *
 * It is not gone: the «کد» tab beside the preview shows the delivered file
 * itself. Here it is hidden rather than removed, so a build that fails can
 * hand it straight back.
 */
.bf-msg--filed .bf-code[data-file] { display: none; }

/*
 * The fold that used to hold that code is gone with it.
 *
 * `.bf-folded` was a `<details>` wrapped round every `<pre>` once a
 * delivery existed. Nothing builds one any more — the code has a place of
 * its own beside the page — so its rules are removed rather than left to
 * read as something the product still does.
 */


/* =====================================================================
 * The model picker's search and filters
 *
 * Colours read from the reference rather than chosen: the panel #10100F,
 * a row #0E0E0E, the search field #161616, a filter pill #2A2A2A.
 *
 * The field narrows by name and the pills narrow by purpose — the
 * second is the more useful, since a person usually knows what they
 * want done and not which model does it.
 * ================================================================== */

.bf-picker__filters {
  display: flex;
  gap: 6px;
  margin: 0 0 8px;
}

.bf-picker__filter {
  flex: 1;
  min-width: 0;
  height: 30px;
  padding: 0 6px;
  border: 1px solid rgba(255,255,255,.07);
  border-radius: 8px;
  background: #161616;
  color: var(--text-secondary);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: var(--bf-ease-all);
}

.bf-picker__filter:hover { border-color: rgba(255,255,255,.14); color: var(--text-primary); }

/*
 * The chosen filter takes the outline, not a fill.
 *
 * The same rule the chosen row follows: orange marks a position, and a
 * filled pill would compete with the row it is filtering to.
 */
.bf-picker__filter.is-on {
  border-color: var(--orange-500);
  color: var(--text-primary);
}

/*
 * The level a model sits at, in three greys.
 *
 * Not orange: that colour already means "this is chosen", and a second
 * meaning would make the picked row say two things at once. The steps
 * differ in lightness alone — "حرفه‌ای" is brighter, not better.
 */
.bf-picker__level {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 9px;
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 6px;
  background: #151515;
  color: #9A9A9A;
  font-size: 11px;
  line-height: 1;
  white-space: nowrap;
}

.bf-picker__level--low  { border-color: rgba(255,255,255,.07); color: #7A7A7A; }
.bf-picker__level--high { border-color: rgba(255,255,255,.20); color: #D6D6D6; }

/* Nothing matched the search or the filter. */
.bf-picker__none {
  margin: 0;
  padding: 20px 12px;
  text-align: center;
  color: var(--text-muted);
  font-size: 12.5px;
}

/* =====================================================================
 * The head of a reply while it is being written
 *
 * An orb where the avatar goes, and one line of live text beside it.
 * Both are removed when the reply finishes and the message settles
 * into its ordinary shape.
 *
 * Figures from the handoff: a 32px orb, 10px of gap, a 34px minimum
 * row so the line does not jump as the orb appears.
 * ================================================================== */

.bf-msg__head {
  display: flex;
  align-items: center;
  gap: 10px;

  /* Tall enough for the orb, or the bar clips what it was widened to show. */
  min-height: 42px;
  margin-bottom: 8px;
  color: var(--text-secondary);
  font-size: 13.5px;
}

/*
 * The orb keeps its box whatever the canvas does.
 *
 * `flex: 0 0 auto` rather than a width alone: the component sizes the
 * canvas itself, and a flex item that can shrink would squeeze it on a
 * narrow screen and leave the drawing clipped.
 */
.bf-msg__head .bf-orb {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
}

/*
 * The status line's own colours.
 *
 * The component reads these four variables and styles itself under
 * `.ai-status`; nothing here reaches inside it.
 */
.bf-msg__head .bf-status {
  --ai-status-color: var(--text-secondary);
  --ai-status-shine: var(--text-primary);
  --ai-status-time:  var(--text-muted);
  --ai-status-error: var(--bf-danger);

  min-width: 0;
}


/*
 * Lists, now that the renderer makes them.
 *
 * Inside a pre-wrap body the markup carries its own newlines, so the list
 * resets that for itself — otherwise every item gains a blank line from the
 * source text that produced it.
 */
.bf-msg__body ul,
.bf-msg__body ol {
  white-space: normal;
  margin: var(--bf-space-2) 0;
  padding-inline-start: 1.6em;
}

.bf-msg__body li {
  margin: 4px 0;
  line-height: 1.9;
}

.bf-msg__body li::marker {
  color: var(--bf-text-muted);
}

/*
 * A cited source has to be visibly clickable, or it is decoration.
 */
.bf-msg__body a {
  color: var(--orange-400);
  text-decoration: underline;
  text-underline-offset: 3px;
  word-break: break-all;
}

.bf-msg__body a:hover {
  color: var(--orange-500);
}


/*
 * The web-search mark in the model picker.
 *
 * Sits beside the vendor name rather than on its own row: it is a property of
 * the model, like the vendor, and a separate line would make every card taller
 * for a detail most people read once.
 */
.bf-picker__web {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-inline-start: 8px;
  padding: 1px 7px 2px;
  border: 1px solid color-mix(in srgb, var(--orange-500) 40%, transparent);
  border-radius: 999px;
  color: var(--orange-400);
  font-size: 11px;
  line-height: 1.6;
  white-space: nowrap;
}

.bf-picker__web svg {
  flex: 0 0 auto;
}


/*
 * The search switch, beside the thinking one.
 *
 * It borrows `.bf-think` wholesale so the two read as one pair rather than
 * two controls that happen to sit together. Only the accent differs, because
 * this one spends money when it is on and that is worth a glance.
 */
.bf-think--search input:checked ~ .bf-think__track {
  background: color-mix(in srgb, var(--orange-500) 55%, transparent);
  border-color: var(--orange-500);
}

@media (max-width: 520px) {
  /* Two switches and a send button do not fit; the label goes, the switch
     stays, and the title attribute still explains it. */
  .bf-think--search .bf-think__label {
    display: none;
  }
}


/*
 * The archive warning.
 *
 * Set apart from the file listing rather than styled like it: it says the
 * listing is not the whole story, so it must not read as another row in it.
 */
.bf-archive__warn {
  margin: 0 0 12px;
  padding: 12px 14px;
  border: 1px solid color-mix(in srgb, var(--bf-danger) 40%, transparent);
  border-radius: 12px;
  background: color-mix(in srgb, var(--bf-danger) 8%, transparent);
  font-size: 13px;
  line-height: 1.8;
}

.bf-archive__warn p { margin: 0; }
.bf-archive__warn ul { margin: 6px 0; padding-inline-start: 18px; }
.bf-archive__warn li { font-size: 12.5px; }

.bf-archive__warn-why {
  margin-top: 6px;
  color: var(--text-secondary);
}

/*
 * The button that asks for the fix.
 *
 * Inside the warning rather than beside it: it is the answer to what the
 * warning says, and a reader who sees the problem should see the way out in
 * the same glance.
 */
.bf-archive__warn-fix {
  margin-top: 10px;
  padding: 7px 16px;
  border: 0;
  border-radius: 10px;
  background: var(--orange-500);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.bf-archive__warn-fix:hover { background: var(--orange-400); }
.bf-archive__warn-fix:disabled { opacity: .55; cursor: default; }

/*
 * The first line of the warning block.
 *
 * There was a second, heavier variant here for blocking findings. Once the
 * gate began stopping those before an archive exists, nothing could ever
 * carry it — a rule for a state the code cannot reach is a rule someone will
 * later maintain for nothing.
 */
.bf-archive__warn-head {
  font-weight: 600;
  color: var(--bf-text);
}

/*
 * A delivery that was refused.
 *
 * Deliberately not shaped like the archive card. That card means "here is
 * your file"; this one means there is no file, and the two must not be
 * distinguishable only by their text.
 */
.bf-blocked {
  margin: 12px 0 0;
  padding: 14px 16px;
  border: 1px solid color-mix(in srgb, var(--bf-danger) 55%, transparent);
  border-inline-start: 3px solid var(--bf-danger);
  border-radius: 12px;
  background: color-mix(in srgb, var(--bf-danger) 12%, transparent);
  font-size: 13px;
  line-height: 1.9;
}

.bf-blocked__head {
  margin: 0;
  color: var(--bf-danger);
  font-size: 14px;
  font-weight: 700;
}

.bf-blocked__why {
  margin: 4px 0 0;
  color: var(--text-secondary);
}

.bf-blocked__list {
  margin: 8px 0 0;
  padding-inline-start: 18px;
}

.bf-blocked__list li { margin-bottom: 4px; }

.bf-blocked__where {
  font-weight: 600;
  color: var(--bf-text);
}

.bf-blocked__rule {
  margin-inline-start: 6px;
  padding: 1px 6px;
  border-radius: 6px;
  background: rgba(255, 255, 255, .07);
  color: var(--text-secondary);
  font-size: var(--bf-size-2xs);
}

.bf-blocked__fix {
  margin-top: 12px;
  padding: 8px 16px;
  border: 0;
  border-radius: 10px;
  background: var(--orange-500);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.bf-blocked__fix:hover { background: var(--orange-400); }
.bf-blocked__fix:disabled { opacity: .55; cursor: default; }


/*
 * A refused delivery.
 *
 * Shaped unlike the download card on purpose: there is no file behind it, and
 * anything that resembles the card that normally carries one sends the reader
 * looking for a link that does not exist.
 */
.bf-reject {
  margin: 10px 0 12px;
  padding: 14px 16px;
  border: 1px solid color-mix(in srgb, var(--bf-danger) 45%, transparent);
  border-radius: 14px;
  background: color-mix(in srgb, var(--bf-danger) 7%, transparent);
  font-size: 13px;
  line-height: 1.9;
}

.bf-reject__head { margin: 0 0 8px; font-weight: 600; }
.bf-reject__list { margin: 0; padding-inline-start: 18px; }
.bf-reject__list li { margin-bottom: 6px; }
.bf-reject__where { display: block; font-size: 12px; color: var(--orange-400); }
.bf-reject__list em { font-style: normal; color: var(--text-secondary); }

.bf-reject__limit {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}

.bf-reject__fix {
  margin-top: 12px;
  padding: 7px 16px;
  border: 0;
  border-radius: 10px;
  background: var(--orange-500);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.bf-reject__fix:disabled { opacity: .55; cursor: default; }


/*
 * The attachment tray, now inside the composer.
 *
 * `.bf-input` is a single flex row, so a child cannot sit above another child
 * without the row being allowed to wrap — `order: -1` alone put the tray
 * first in the row, not above it. Measured in a browser: the tray's bottom
 * edge was 34px below the send button's top edge, which is the opposite of
 * what was asked for.
 *
 * With wrapping on and a full basis, the tray takes a line of its own and
 * everything else keeps the row it had.
 */
.bf-input { flex-wrap: wrap; }

.bf-input .bf-attach {
  order: -1;
  flex: 0 0 100%;
  width: 100%;
  margin: 0 0 10px;
}

.bf-input .bf-attach[hidden] { display: none; }


/*
 * THE BOX A MESSAGE IS WRITTEN IN, ON A PHONE.
 *
 * The owner photographed his own site: a model with several options, and
 * the writing box so narrow that each word went onto its own line, down
 * the screen. Measured on the real composer at three phone widths:
 *
 *     360px screen →  34px   about 4 characters
 *     390px screen →  18px   about 2 characters
 *     414px screen →  42px   about 5 characters
 *
 * Nothing else caught it and nothing else could have. The composer does
 * not overflow, its buttons are large enough, its text is not small — the
 * page is fine and the box is unusable. Every check here measured what
 * SPILLS; this is the first one that measures what is LEFT.
 *
 * The cause is one line: the textarea is `flex: 1; min-width: 0`, so it
 * gives up its width to whatever else is on the row rather than pushing
 * anything to the next one. With two chips there, there is nothing to give.
 *
 * So on a phone the writing box takes the first line to itself and
 * everything that acts on it sits underneath — which is also what the
 * owner asked for. The row stays inside the same box, so the thing being
 * written and the button that sends it are still one object; that was the
 * reason the controls were put in this row in the first place and it is
 * not given up.
 */
@media (max-width: 640px) {
  .bf-input { align-items: center; row-gap: 8px; }

  /* Above the writing box, not beside it. */
  .bf-input .bf-attach { order: -2; }

  .bf-input textarea {
    order: -1;
    flex: 1 0 100%;
    padding: 8px 10px;
  }

  /* Send at the far end of the row below, in both directions. */
  .bf-input .bf-send { margin-inline-start: auto; }
}


/*
 * Where a message's file card lives: after the answer, before the actions.
 *
 * The card used to be inserted as the message's first child, so the download
 * appeared above the answer that produced it. It is now a real slot in the
 * DOM rather than a visual reordering, so the reading order and the seen
 * order are the same.
 *
 * No box of its own, and nothing when it is empty — a message that produced
 * no file must not carry a gap where one would have been.
 */
.bf-msg__artifacts { display: block; }
.bf-msg__artifacts:empty { display: none; }
.bf-msg__artifacts > * { margin-top: 12px; }

/*
 * The delivery card.
 *
 * One row per file: icon, name and type, then the actions. Sizes are the
 * design's own, read from filecards.html rather than measured off a picture.
 *
 * Colour comes from the site's tokens, not the design's — its orange is
 * #B76B52 and the brand is #A94F31, and its surfaces are warm where the rest
 * of this site is neutral. A card that matched the design exactly would not
 * match the page it sits on.
 */
.bf-archive__cards {
  display: block;
}

.bf-fc {
  /*
   * Left to right inside the row — icon, name, actions — which is how the
   * design has it, even though the page is right to left. Each label still
   * shapes right to left inside its own box.
   */
  direction: ltr;
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 18px 20px;
  margin-bottom: 14px;
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  background: var(--surface-4);
}

.bf-fc:last-child { margin-bottom: 0; }

/*
 * The sheet is drawn, so the box around it holds nothing of its own.
 *
 * This was a 78-pixel square filled with a gradient, with the extension set
 * in small letters at its centre — the shape a file badge had in desktop
 * software a decade ago, and it dominated a row whose subject is the file's
 * NAME. The mark is 56 now and carries its own colour; the container only
 * reserves the space.
 */
.bf-fc__icon {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
}

.bf-fc__icon svg { display: block; }

.bf-fc__meta {
  flex: 1;
  min-width: 0;
  direction: ltr;
  text-align: left;
}

.bf-fc__name {
  display: block;
  font-size: 17px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bf-fc__kind {
  display: block;
  margin-top: 4px;
  color: var(--text-muted);
  font-size: 14px;
  direction: rtl;
  text-align: left;
}

/*
 * `12.4 MB` renders as `MB 12.4` inside a right-to-left run.
 *
 * The reversal is real: measured in a right-to-left container, `12.4 MB` puts
 * its first character to the right of its last. What is *not* true is that
 * this particular line is doing the work — the direction is already inherited
 * from `.bf-fc`, and removing it here, and from `.bf-fc__meta`, and from the
 * row itself, left the text reading correctly all three times. Something
 * further up the page provides it.
 *
 * Kept anyway, because it costs nothing and the card should not depend on an
 * ancestor nobody has written down. A size that silently reverses is the kind
 * of fault nobody reports.
 */
.bf-fc__size {
  display: block;
  margin-top: 2px;
  color: var(--text-muted);
  font-size: 14px;
  direction: ltr;
  text-align: left;
}

.bf-fc__acts {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.bf-fc__btn {
  /*
   * The icon sits to the right of the label. Neither `row-reverse` nor
   * `direction` alone does that inside a right-to-left page — they cancel
   * out. With `direction: ltr` and a plain row the first child sits on the
   * left, so the label is written first and the icon lands after it.
   */
  direction: ltr;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 172px;
  height: 46px;
  border-radius: 10px;
  border: 0;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.bf-fc__btn > span { direction: rtl; }
.bf-fc__btn > svg { flex: none; }

.bf-fc__btn--solid { background: var(--orange-500); color: #fff; }
.bf-fc__btn--solid:hover { background: var(--orange-400); color: #fff; }

.bf-fc__btn--ghost {
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border-strong);
}

.bf-fc__btn--ghost:hover { border-color: var(--orange-border); color: var(--orange-400); }

/*
 * Narrow screens.
 *
 * At the design's widths the actions column and a 78px icon leave the name
 * about 90px on a phone, which is not enough for a filename. The row stacks
 * instead and the buttons take the full width.
 */
@media (max-width: 640px) {
  .bf-fc {
    flex-wrap: wrap;
    gap: 14px;
    padding: 14px;
  }

  .bf-fc__meta { flex: 1 1 100%; order: 2; }
  .bf-fc__acts { flex: 1 1 100%; order: 3; flex-direction: row; }
  .bf-fc__btn { width: auto; flex: 1; }
}


/* =====================================================================
 * No tile in the chat picker — the mark alone
 *
 * The mark sat in a bordered square that added nothing: it is one model,
 * already named beside it, so there is nothing for the square to separate
 * it from. Without the box the mark can be larger in the same space and
 * reads at a glance.
 * ================================================================== */
.bf-picker__btn .bf-model-logo {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 0;
  line-height: 0;
  overflow: visible;
}

.bf-picker__btn .bf-model-logo img,
.bf-picker__btn .bf-model-logo svg {
  display: block;
  /*
   * Larger, because nothing frames it now.
   *
   * At 22px inside a 24px box it read as small next to the model's name;
   * with the square gone there is no edge for it to respect, so it takes
   * the room the text beside it occupies.
   */
  width: 28px;
  height: 28px;
  object-fit: contain;
  margin: 0;
}

/* =====================================================================
 * The conversation history, in a sheet
 *
 * A column of every conversation ever started pushed the workspaces and
 * the balance off the bottom of the rail, and got worse the more the
 * site was used. Behind a button it is one press away and costs nothing
 * until then.
 *
 * The page behind is blurred rather than merely darkened: dimming alone
 * leaves the text underneath legible enough to compete for the eye.
 * ================================================================== */

.bf-hist__open {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--bf-line);
  border-radius: 10px;
  background: var(--surface-3);
  color: var(--bf-text);
  font-family: inherit;
  font-size: var(--bf-size-sm);
  font-weight: 600;
  cursor: pointer;
  transition: var(--bf-ease-all);
}

.bf-hist__open:hover {
  background: rgba(255, 255, 255, .05);
  border-color: var(--bf-line-strong);
}

.bf-hist__open svg {
  flex: none;
  width: 17px;
  height: 17px;
  color: var(--orange-400);
}

.bf-hist__open span {
  flex: 1;
  text-align: start;
}

.bf-hist__caret {
  width: 15px !important;
  height: 15px !important;
  color: var(--bf-text-dim) !important;
}

/* ---- the sheet ------------------------------------------------------ */

.bf-hist__dim {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(6, 6, 6, .55);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
}

.bf-hist__dim[hidden] { display: none !important; }

.bf-hist {
  position: fixed;
  inset-block: 0;

  /*
   * On the side the rail is on.
   *
   * `inset-inline-end` resolves to the left in a right-to-left page, so
   * the sheet opened on the opposite side from the button that summons
   * it — the eye follows the press to one edge and the panel appears at
   * the other.
   */
  inset-inline-start: 0;
  z-index: 61;

  /*
   * Half the screen, and never so narrow that a title has to wrap, nor
   * so wide that the page behind stops being visible — the blur is what
   * says the sheet is temporary, and it only reads that way if there is
   * something to see through it.
   */
  width: clamp(320px, 50vw, 560px);

  display: flex;
  flex-direction: column;
  border-inline-end: 1px solid var(--bf-line);
  background: var(--surface-2);
  box-shadow: 24px 0 60px rgba(0, 0, 0, .45);
}

.bf-hist[hidden] { display: none !important; }

.bf-hist__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;
  padding: 18px 20px;
  border-bottom: 1px solid var(--bf-line);
}

.bf-hist__head h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--bf-text);
}

.bf-hist__close {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--bf-line);
  border-radius: 9px;
  background: transparent;
  color: var(--bf-text-muted);
  cursor: pointer;
  transition: var(--bf-ease-all);
}

.bf-hist__close:hover {
  background: rgba(255, 255, 255, .05);
  color: var(--bf-text);
}

.bf-hist__close svg {
  width: 16px;
  height: 16px;
}

/*
 * The list keeps its own styling and simply scrolls inside the sheet.
 */
.bf-hist .bf-rail__list {
  flex: 1;
  overflow-y: auto;
  padding: 14px 16px 20px;
}

@media (max-width: 700px) {
  .bf-hist { width: 100%; }
}
