    /* ========================================
       JARVIS DESIGN SYSTEM
       ======================================== */
    :root {
      /* Colors */
      --bg-deep: #060b18;
      --bg-panel: #0d1525;
      --bg-card: rgba(13, 21, 37, 0.7);
      --bg-card-hover: rgba(13, 21, 37, 0.9);
      --bg-sidebar: rgba(8, 14, 28, 0.85);

      --cyan: #00d4ff;
      --cyan-dim: rgba(0, 212, 255, 0.15);
      --cyan-glow: rgba(0, 212, 255, 0.3);
      --cyan-bright: #00f0ff;
      --gold: #f0b429;
      --gold-dim: rgba(240, 180, 41, 0.15);
      --red: #ff3b3b;
      --green: #00ff88;
      --green-dim: rgba(0, 255, 136, 0.15);

      --text-primary: #e8edf5;
      --text-secondary: rgba(232, 237, 245, 0.4);
      --text-tertiary: rgba(232, 237, 245, 0.2);

      --border: rgba(0, 212, 255, 0.1);
      --border-hover: rgba(0, 212, 255, 0.3);

      /* Typography */
      --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
      --font-mono: 'JetBrains Mono', 'Fira Code', monospace;

      /* Spacing */
      --sidebar-width: 210px;
      --header-height: 60px;

      /* Transitions */
      --ease: cubic-bezier(0.4, 0, 0.2, 1);
    }

    /* ========================================
       RESET & BASE
       ======================================== */
    *, *::before, *::after {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    html {
      font-size: 16px;
      scroll-behavior: smooth;
    }

    body {
      font-family: var(--font-sans);
      background: var(--bg-deep);
      color: var(--text-primary);
      min-height: 100vh;
      overflow-x: hidden;
      line-height: 1.6;
    }

    /* ========================================
       BACKGROUND EFFECTS
       ======================================== */
    body::before {
      content: '';
      position: fixed;
      inset: 0;
      background:
        radial-gradient(ellipse at 20% 50%, rgba(0, 212, 255, 0.03) 0%, transparent 60%),
        radial-gradient(ellipse at 80% 20%, rgba(240, 180, 41, 0.02) 0%, transparent 50%),
        radial-gradient(ellipse at 50% 100%, rgba(0, 212, 255, 0.02) 0%, transparent 40%);
      pointer-events: none;
      z-index: 0;
    }

    /* Scanline overlay */
    body::after {
      content: '';
      position: fixed;
      inset: 0;
      background: repeating-linear-gradient(
        0deg,
        transparent,
        transparent 2px,
        rgba(0, 212, 255, 0.008) 2px,
        rgba(0, 212, 255, 0.008) 4px
      );
      pointer-events: none;
      z-index: 9999;
    }

    /* Grid pattern */
    .grid-pattern {
      position: fixed;
      inset: 0;
      background-image:
        linear-gradient(rgba(0, 212, 255, 0.02) 1px, transparent 1px),
        linear-gradient(90deg, rgba(0, 212, 255, 0.02) 1px, transparent 1px);
      background-size: 60px 60px;
      pointer-events: none;
      z-index: 0;
    }

    /* ========================================
       BOOT SEQUENCE
       ======================================== */
    #boot-screen {
      position: fixed;
      inset: 0;
      z-index: 10000;
      background: var(--bg-deep);
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      transition: opacity 0.8s var(--ease), visibility 0.8s;
    }

    #boot-screen.dismissed {
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
    }

    .arc-reactor {
      width: 160px;
      height: 160px;
      position: relative;
      margin-bottom: 40px;
    }

    .arc-reactor .ring {
      position: absolute;
      inset: 0;
      border-radius: 50%;
      border: 2px solid transparent;
    }

    .arc-reactor .ring-1 {
      inset: 0;
      border-color: var(--cyan);
      opacity: 0.6;
      animation: spin-cw 4s linear infinite;
      border-top-color: transparent;
      border-left-color: transparent;
    }

    .arc-reactor .ring-2 {
      inset: 15px;
      border-color: var(--cyan-bright);
      opacity: 0.4;
      animation: spin-ccw 3s linear infinite;
      border-bottom-color: transparent;
      border-right-color: transparent;
    }

    .arc-reactor .ring-3 {
      inset: 30px;
      border-color: var(--cyan);
      opacity: 0.8;
      animation: spin-cw 2s linear infinite;
      border-top-color: transparent;
    }

    .arc-reactor .core {
      position: absolute;
      inset: 45px;
      border-radius: 50%;
      background: radial-gradient(circle, var(--cyan-bright) 0%, var(--cyan) 40%, transparent 70%);
      box-shadow: 0 0 40px var(--cyan-glow), 0 0 80px var(--cyan-dim), inset 0 0 20px rgba(0, 240, 255, 0.3);
      animation: pulse-core 2s ease-in-out infinite;
    }

    .arc-reactor .core-dot {
      position: absolute;
      inset: 55px;
      border-radius: 50%;
      background: white;
      opacity: 0.9;
      box-shadow: 0 0 15px white;
    }

    @keyframes spin-cw { to { transform: rotate(360deg); } }
    @keyframes spin-ccw { to { transform: rotate(-360deg); } }
    @keyframes pulse-core {
      0%, 100% { opacity: 0.8; transform: scale(1); }
      50% { opacity: 1; transform: scale(1.05); }
    }

    .boot-title {
      font-family: var(--font-sans);
      font-size: 2.5rem;
      font-weight: 700;
      letter-spacing: 0.35em;
      text-transform: uppercase;
      color: var(--text-primary);
      margin-bottom: 32px;
      text-shadow: 0 0 30px var(--cyan-dim);
    }

    .boot-title span {
      color: var(--cyan);
    }

    .boot-progress {
      width: 320px;
      margin-bottom: 32px;
    }

    .boot-progress-bar {
      height: 3px;
      background: rgba(255, 255, 255, 0.05);
      border-radius: 2px;
      overflow: hidden;
      margin-bottom: 8px;
    }

    .boot-progress-fill {
      height: 100%;
      background: linear-gradient(90deg, var(--cyan), var(--cyan-bright));
      border-radius: 2px;
      width: 0%;
      transition: width 0.3s var(--ease);
      box-shadow: 0 0 10px var(--cyan-glow);
    }

    .boot-progress-text {
      font-family: var(--font-mono);
      font-size: 0.7rem;
      color: var(--text-secondary);
      text-align: center;
      letter-spacing: 0.1em;
    }

    .boot-log {
      font-family: var(--font-mono);
      font-size: 0.75rem;
      color: var(--text-secondary);
      text-align: left;
      width: 320px;
    }

    .boot-log-entry {
      opacity: 0;
      transform: translateY(5px);
      transition: opacity 0.3s, transform 0.3s;
      margin-bottom: 4px;
    }

    .boot-log-entry.visible {
      opacity: 1;
      transform: translateY(0);
    }

    .boot-log-entry .check {
      color: var(--green);
      margin-right: 6px;
    }

    .boot-log-entry .label {
      color: var(--text-secondary);
    }

    /* ========================================
       APP LAYOUT
       ======================================== */
    #app {
      display: flex;
      /* Altezza fissa, non min-height: la console non scrolla come pagina, sono
         i singoli pannelli a scrollare. dvh dopo vh perche' la barra URL di
         Safari/Firefox iOS taglia 100vh, ed e' li' che la chat diventava
         inusabile su iPad. */
      height: 100vh;
      height: 100dvh;
      overflow: hidden;
      opacity: 0;
      transition: opacity 0.6s var(--ease) 0.3s;
      position: relative;
      z-index: 1;
    }

    #app.visible {
      opacity: 1;
    }

    /* ========================================
       SIDEBAR
       ======================================== */
    .sidebar {
      width: var(--sidebar-width);
      background: var(--bg-sidebar);
      backdrop-filter: blur(20px);
      border-right: 1px solid var(--border);
      display: flex;
      flex-direction: column;
      padding: 16px 0;
      position: fixed;
      top: 0;
      left: 0;
      bottom: 0;
      z-index: 100;
    }

    .sidebar-logo {
      width: 40px;
      height: 40px;
      margin: 0 auto 26px;
      position: relative;
    }

    .sidebar-logo .mini-reactor {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      background: radial-gradient(circle, var(--cyan-bright) 0%, var(--cyan) 30%, transparent 70%);
      box-shadow: 0 0 15px var(--cyan-dim);
      animation: pulse-core 3s ease-in-out infinite;
    }

    .sidebar-nav {
      display: flex;
      flex-direction: column;
      gap: 2px;
      flex: 1;
      width: 100%;
      padding: 0 10px;
    }

    /* ═══ CONSOLE A: menu con etichette e gruppi ═══
       Le voci erano icone mute con un tooltip su :hover. Il tooltip e' stato
       tolto del tutto, non nascosto: sopra i 768px l'etichetta e' in chiaro e
       non serve, sotto i 768px la sidebar e' una barra su un dispositivo touch,
       dove :hover o non scatta mai o resta incollato dopo un tap.

       Le voci sono SOLO quelle che aprono un pannello reale. Stessa regola gia'
       applicata al marketing (vedi renderMktGate): una voce che non porta da
       nessuna parte sembra un guasto, non una feature assente. */
    .nav-group {
      font-family: var(--font-mono);
      font-size: 9.5px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--text-tertiary);
      padding: 0 12px 7px;
      margin-top: 18px;
    }
    .nav-group:first-child { margin-top: 0; }

    .nav-item {
      width: 100%;
      height: 38px;
      display: flex;
      align-items: center;
      gap: 11px;
      padding: 0 12px;
      border-radius: 9px;
      cursor: pointer;
      transition: all 0.2s var(--ease);
      color: var(--text-secondary);
      position: relative;
    }

    .nav-item .label {
      font-size: 13px;
      font-weight: 500;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .nav-item:hover {
      background: var(--cyan-dim);
      color: var(--cyan);
    }

    .nav-item.active {
      background: var(--cyan-dim);
      color: var(--cyan);
    }

    .nav-item.active::before {
      content: '';
      position: absolute;
      left: -10px;
      top: 50%;
      transform: translateY(-50%);
      width: 3px;
      height: 24px;
      background: var(--cyan);
      border-radius: 0 3px 3px 0;
    }

    .nav-item svg {
      width: 18px;
      height: 18px;
      flex-shrink: 0;
    }


    /* ========================================
       MAIN CONTENT
       ======================================== */
    .main {
      flex: 1;
      min-width: 0;
      height: 100%;
      overflow: hidden;
      margin-left: var(--sidebar-width);
      display: flex;
      flex-direction: column;
    }

    /* Header */
    .header {
      height: var(--header-height);
      flex-shrink: 0;
      border-bottom: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 32px;
      background: rgba(6, 11, 24, 0.6);
      backdrop-filter: blur(20px);
      position: sticky;
      top: 0;
      z-index: 50;
    }

    .header-left {
      display: flex;
      align-items: center;
      gap: 16px;
    }

    .header-brand {
      font-size: 1.1rem;
      font-weight: 700;
      letter-spacing: 0.2em;
      text-transform: uppercase;
      color: var(--text-primary);
    }

    .header-brand span {
      color: var(--cyan);
    }

    .header-sub {
      font-family: var(--font-mono);
      font-size: 0.7rem;
      color: var(--text-secondary);
      letter-spacing: 0.05em;
    }

    .header-right {
      display: flex;
      align-items: center;
      gap: 16px;
    }

    .status-badge {
      display: flex;
      align-items: center;
      gap: 8px;
      /* .header ha altezza fissa e nessun overflow: se il testo del badge va
         a capo, le righe in piu' escono dal basso e coprono il contenuto.
         Il difetto e' nato con la sidebar a 210px (CP1), che ha tolto 138px
         all'header — non con la traduzione, che ha accorciato la stringa. */
      white-space: nowrap;
      padding: 6px 14px;
      border-radius: 20px;
      font-size: 0.75rem;
      font-weight: 500;
      font-family: var(--font-mono);
    }

    .status-badge.online {
      background: var(--green-dim);
      color: var(--green);
      border: 1px solid rgba(0, 255, 136, 0.2);
    }

    .status-badge.offline {
      background: rgba(255, 59, 59, 0.1);
      color: var(--red);
      border: 1px solid rgba(255, 59, 59, 0.2);
    }

    .status-dot {
      width: 7px;
      height: 7px;
      border-radius: 50%;
      animation: blink 2s ease-in-out infinite;
    }

    .status-badge.online .status-dot {
      background: var(--green);
      box-shadow: 0 0 6px var(--green);
    }

    .status-badge.offline .status-dot {
      background: var(--red);
      box-shadow: 0 0 6px var(--red);
      animation: none;
    }

    @keyframes blink {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.4; }
    }

    /* Content area — contenitore dei pannelli.
       min-height:0 e' obbligatorio: senza, un figlio flex non scrolla mai
       perche' la sua base e' il contenuto, non il contenitore. */
    .content {
      flex: 1;
      min-height: 0;
      width: 100%;
      overflow: hidden;
      position: relative;
    }

    /* ========================================
       SECTION: SYSTEM VITALS
       ======================================== */
    .vitals {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 16px;
      margin-bottom: 40px;
    }

    .vital-card {
      background: var(--bg-card);
      backdrop-filter: blur(20px);
      border: 1px solid var(--border);
      border-radius: 16px;
      padding: 20px 24px;
      transition: all 0.3s var(--ease);
      position: relative;
      overflow: hidden;
    }

    .vital-card::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 2px;
      background: linear-gradient(90deg, transparent, var(--cyan), transparent);
      opacity: 0;
      transition: opacity 0.3s;
    }

    .vital-card:hover {
      border-color: var(--border-hover);
      transform: translateY(-2px);
      background: var(--bg-card-hover);
    }

    .vital-card:hover::before {
      opacity: 1;
    }

    .vital-value {
      font-size: 2rem;
      font-weight: 800;
      color: var(--cyan);
      font-family: var(--font-mono);
      margin-bottom: 4px;
      line-height: 1.1;
    }

    .vital-label {
      font-size: 0.75rem;
      color: var(--text-secondary);
      text-transform: uppercase;
      letter-spacing: 0.1em;
      font-weight: 500;
    }

    .vital-icon {
      position: absolute;
      top: 16px;
      right: 16px;
      color: var(--text-tertiary);
      font-size: 1.5rem;
    }

    /* ========================================
       SECTION: CAPABILITIES GRID
       ======================================== */
    .section-header {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-bottom: 24px;
    }

    .section-header h2 {
      font-size: 1rem;
      font-weight: 600;
      letter-spacing: 0.15em;
      text-transform: uppercase;
      color: var(--text-primary);
    }

    .section-header .line {
      flex: 1;
      height: 1px;
      background: linear-gradient(90deg, var(--border-hover), transparent);
    }

    .section-header .count {
      font-family: var(--font-mono);
      font-size: 0.7rem;
      color: var(--gold);
      background: var(--gold-dim);
      padding: 3px 10px;
      border-radius: 10px;
    }

    .capabilities {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 20px;
      margin-bottom: 48px;
    }

    .cap-card {
      background: var(--bg-card);
      backdrop-filter: blur(20px);
      border: 1px solid var(--border);
      border-radius: 16px;
      padding: 28px;
      transition: all 0.3s var(--ease);
      cursor: default;
      position: relative;
      overflow: hidden;
    }

    .cap-card::after {
      content: '';
      position: absolute;
      inset: 0;
      border-radius: 16px;
      border: 1px solid transparent;
      background: linear-gradient(135deg, var(--cyan-dim), transparent, transparent) border-box;
      -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
      -webkit-mask-composite: xor;
      mask-composite: exclude;
      opacity: 0;
      transition: opacity 0.3s;
    }

    .cap-card:hover {
      transform: translateY(-4px);
      border-color: var(--border-hover);
      box-shadow: 0 8px 32px rgba(0, 212, 255, 0.06);
      background: var(--bg-card-hover);
    }

    .cap-card:hover::after {
      opacity: 1;
    }

    .cap-icon {
      width: 48px;
      height: 48px;
      border-radius: 12px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 1.4rem;
      margin-bottom: 20px;
      position: relative;
    }

    .cap-icon.memory { background: rgba(0, 212, 255, 0.1); }
    .cap-icon.skills { background: rgba(240, 180, 41, 0.1); }
    .cap-icon.google { background: rgba(0, 255, 136, 0.1); }
    .cap-icon.wiki   { background: rgba(0, 212, 255, 0.1); }
    .cap-icon.media  { background: rgba(167, 139, 250, 0.1); }
    .cap-icon.intel  { background: rgba(240, 180, 41, 0.1); }

    .cap-card h3 {
      font-size: 1rem;
      font-weight: 600;
      margin-bottom: 8px;
      color: var(--text-primary);
    }

    .cap-card p {
      font-size: 0.825rem;
      color: var(--text-secondary);
      line-height: 1.6;
      margin-bottom: 16px;
    }

    .cap-tags {
      display: flex;
      flex-wrap: wrap;
      gap: 6px;
    }

    .cap-tag {
      font-family: var(--font-mono);
      font-size: 0.65rem;
      padding: 3px 8px;
      border-radius: 6px;
      background: rgba(255, 255, 255, 0.04);
      color: var(--text-secondary);
      border: 1px solid rgba(255, 255, 255, 0.05);
    }

    .cap-tag.highlight {
      background: var(--cyan-dim);
      color: var(--cyan);
      border-color: rgba(0, 212, 255, 0.15);
    }

    /* ========================================
       SECTION: WIKI KNOWLEDGE BROWSER
       ======================================== */
    .wiki-section {
      margin-bottom: 48px;
    }

    /* Il markup che usa queste regole e' stato tolto: elencava pagine
       inventate. Le regole restano perche' l'elenco vero avra' la stessa
       forma, quando un endpoint lo esporra' per categoria. */
    .wiki-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 20px;
    }

    .wiki-category {
      background: var(--bg-card);
      backdrop-filter: blur(20px);
      border: 1px solid var(--border);
      border-radius: 16px;
      padding: 24px;
      transition: all 0.3s var(--ease);
    }

    .wiki-category:hover {
      border-color: var(--border-hover);
    }

    .wiki-cat-header {
      display: flex;
      align-items: center;
      gap: 10px;
      margin-bottom: 16px;
    }

    .wiki-cat-icon {
      font-size: 1.2rem;
    }

    .wiki-cat-name {
      font-size: 0.85rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.1em;
      color: var(--text-primary);
    }

    .wiki-cat-count {
      font-family: var(--font-mono);
      font-size: 0.65rem;
      color: var(--cyan);
      margin-left: auto;
      background: var(--cyan-dim);
      padding: 2px 8px;
      border-radius: 8px;
    }

    .wiki-pages {
      list-style: none;
    }

    .wiki-page-item {
      padding: 8px 12px;
      border-radius: 8px;
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 0.8rem;
      color: var(--text-secondary);
      transition: all 0.2s;
      cursor: default;
    }

    .wiki-page-item:hover {
      background: rgba(255, 255, 255, 0.03);
      color: var(--text-primary);
    }

    .wiki-page-item::before {
      content: '›';
      color: var(--cyan);
      font-weight: 600;
      font-size: 0.9rem;
    }

    /* ========================================
       SECTION: WAT ARCHITECTURE
       ======================================== */
    .architecture-section {
      margin-bottom: 48px;
    }

    .arch-flow {
      display: grid;
      grid-template-columns: 1fr auto 1fr auto 1fr;
      gap: 0;
      align-items: center;
    }

    .arch-block {
      background: var(--bg-card);
      backdrop-filter: blur(20px);
      border: 1px solid var(--border);
      border-radius: 16px;
      padding: 28px;
      text-align: center;
      transition: all 0.3s var(--ease);
    }

    .arch-block:hover {
      border-color: var(--border-hover);
      transform: translateY(-2px);
    }

    .arch-block-icon {
      font-size: 2rem;
      margin-bottom: 12px;
    }

    .arch-block-title {
      font-size: 0.85rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.15em;
      color: var(--cyan);
      margin-bottom: 6px;
    }

    .arch-block-sub {
      font-size: 0.75rem;
      color: var(--text-secondary);
    }

    .arch-block-desc {
      font-family: var(--font-mono);
      font-size: 0.65rem;
      color: var(--text-tertiary);
      margin-top: 8px;
    }

    .arch-arrow {
      display: flex;
      align-items: center;
      justify-content: center;
      color: var(--cyan);
      font-size: 1.5rem;
      padding: 0 8px;
      opacity: 0.4;
    }

    /* ========================================
       COMMAND INTERFACE
       ======================================== */
    .command-section {
      margin-bottom: 48px;
    }

    .command-bar {
      background: var(--bg-card);
      backdrop-filter: blur(20px);
      border: 1px solid var(--border);
      border-radius: 16px;
      padding: 20px 28px;
      display: flex;
      align-items: center;
      gap: 16px;
      transition: all 0.3s var(--ease);
    }

    .command-bar:hover, .command-bar:focus-within {
      border-color: var(--border-hover);
      box-shadow: 0 0 20px var(--cyan-dim);
    }

    .command-prompt {
      color: var(--cyan);
      font-family: var(--font-mono);
      font-size: 0.85rem;
      font-weight: 600;
      white-space: nowrap;
    }

    .command-input {
      flex: 1;
      background: none;
      border: none;
      outline: none;
      font-family: var(--font-mono);
      font-size: 0.85rem;
      color: var(--text-primary);
      caret-color: var(--cyan);
    }

    .command-input::placeholder {
      color: var(--text-tertiary);
    }

    .command-hint {
      font-family: var(--font-mono);
      font-size: 0.65rem;
      color: var(--text-tertiary);
      border: 1px solid var(--border);
      padding: 4px 8px;
      border-radius: 6px;
    }

    /* ========================================
       FOOTER
       ======================================== */
    .footer {
      border-top: 1px solid var(--border);
      padding: 12px 32px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-family: var(--font-mono);
      font-size: 0.65rem;
      color: var(--text-tertiary);
      background: rgba(6, 11, 24, 0.6);
      backdrop-filter: blur(20px);
      flex-shrink: 0;
    }

    .footer-left {
      display: flex;
      align-items: center;
      gap: 24px;
    }

    .footer-right {
      display: flex;
      align-items: center;
      gap: 16px;
    }

    .footer-dot {
      width: 5px;
      height: 5px;
      border-radius: 50%;
      background: var(--green);
      box-shadow: 0 0 4px var(--green);
      display: inline-block;
      margin-right: 4px;
      animation: blink 2s ease-in-out infinite;
    }

    /* ========================================
       SECTION: SOUL / IDENTITY
       ======================================== */
    .soul-section {
      margin-bottom: 48px;
    }

    .soul-card {
      background: var(--bg-card);
      backdrop-filter: blur(20px);
      border: 1px solid var(--border);
      border-radius: 16px;
      padding: 32px;
      position: relative;
      overflow: hidden;
    }

    .soul-card::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 2px;
      background: linear-gradient(90deg, var(--cyan), var(--gold), var(--cyan));
    }

    .soul-quote {
      font-size: 1.15rem;
      font-weight: 300;
      color: var(--text-primary);
      line-height: 1.7;
      font-style: italic;
      margin-bottom: 16px;
      padding-left: 20px;
      border-left: 2px solid var(--cyan);
    }

    .soul-traits {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 12px;
      margin-top: 20px;
    }

    .soul-trait {
      background: rgba(255, 255, 255, 0.02);
      border: 1px solid rgba(255, 255, 255, 0.04);
      border-radius: 10px;
      padding: 14px 16px;
      text-align: center;
    }

    .soul-trait-icon {
      font-size: 1.2rem;
      margin-bottom: 6px;
    }

    .soul-trait-label {
      font-size: 0.7rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.1em;
      color: var(--text-secondary);
    }

    /* ========================================
       CONSOLE: PANNELLI
       ========================================
       La sidebar cambia PANNELLO invece di scrollare la pagina: una schermata =
       una vista. Prima erano tutte sezioni impilate, e la chat finiva schiacciata
       in cima a una vetrina lunga da scrollare. */
    .panel {
      display: none;
      height: 100%;
      overflow-y: auto;
      overflow-x: hidden;
      padding: 26px 32px 40px;
      max-width: 1200px;
      width: 100%;
      margin: 0 auto;
    }

    .panel.active {
      display: block;
      animation: panelIn 0.24s var(--ease);
    }

    /* Il pannello chat e' l'eccezione: NON scrolla lui, scrolla il log al suo
       interno, cosi' il composer resta ancorato in fondo allo schermo invece di
       scappare via insieme al contenuto. */
    .panel.panel-chat {
      overflow: hidden;
      padding: 18px 32px 18px;
    }

    .panel.panel-chat.active {
      display: flex;
      flex-direction: column;
    }

    @keyframes panelIn {
      from { opacity: 0; transform: translateY(6px); }
      to { opacity: 1; transform: none; }
    }

    /* Dentro il pannello chat la shell si allunga fino a riempire lo schermo e
       il log scrolla al suo interno. Il vecchio max-height:62vh serviva quando
       la chat era una sezione in mezzo a una pagina che scrollava: qui
       lascerebbe un buco sotto il composer sugli schermi alti, e la
       tagliuzzerebbe su quelli bassi. */
    /* ═══ CONSOLE A: la terza colonna ═══
       Era una striscia di una riga sopra il composer, che si accendeva a
       meta' turno e si spegneva subito dopo. Ora e' una colonna sempre
       presente, perche' "cosa sta facendo adesso" deve avere un posto anche
       quando la risposta e' "niente".
       E' LO STESSO NODO #chat-activity: sotto i 1100px il media query lo
       rimette in orizzontale. Due elementi diversi sarebbero due destinazioni
       per la stessa scrittura, e in due commit divergerebbero. */
    .panel-chat .chat-shell {
      flex: 1;
      min-height: 0;
      display: grid;
      grid-template-columns: minmax(0, 1fr) 290px;
      /* Cinque righe: registro, composer, allegati, barra documento, riga di
         stato. Allegati e barra documento stanno fra il composer e lo stato
         perche' appartengono al messaggio che stai scrivendo, non alla sessione;
         gli allegati vengono per primi perche' sono il contenuto, la barra e'
         l'istruzione sul formato dell'uscita. */
      grid-template-rows: minmax(0, 1fr) auto auto auto auto;
    }

    .panel-chat .chat-log      { grid-column: 1; grid-row: 1; min-height: 0; max-height: none; }
    .panel-chat .chat-composer { grid-column: 1; grid-row: 2; }
    .panel-chat .alle-zona     { grid-column: 1; grid-row: 3; }
    .panel-chat .doc-bar       { grid-column: 1; grid-row: 4; }
    .panel-chat .chat-meta     { grid-column: 1; grid-row: 5; }

    .panel-chat .chat-activity {
      grid-column: 2; grid-row: 1 / -1;
      min-height: 0; max-height: none; overflow-y: auto;
      border-left: 1px solid var(--border);
      background: rgba(5, 10, 20, .3);
      padding: 15px 16px; transition: none;
      display: block;
    }

    .panel-chat .section-header {
      flex-shrink: 0;
    }

    /* ========================================
       CONSOLE: VITALS IN HEADER
       ========================================
       I quattro riquadri occupavano una fascia intera sotto la chat. Come
       striscia in header restano sempre visibili senza rubarle spazio. */
    .hvitals {
      display: flex;
      align-items: center;
      gap: 20px;
      font-family: var(--font-mono);
      font-size: 0.7rem;
    }

    .hvital {
      display: flex;
      align-items: baseline;
      gap: 6px;
      white-space: nowrap;
    }

    .hvital b {
      color: var(--cyan);
      font-size: 0.95rem;
      font-weight: 600;
    }

    .hvital span {
      color: var(--text-secondary);
      text-transform: uppercase;
      letter-spacing: 0.06em;
    }

    /* ========================================
       CONSOLE: LOGIN (unico punto di accesso)
       ======================================== */
    .btn-login {
      font-family: var(--font-sans);
      font-size: 0.82rem;
      font-weight: 600;
      padding: 7px 16px;
      border-radius: 8px;
      border: 1px solid var(--cyan);
      background: var(--cyan-dim);
      color: var(--cyan);
      cursor: pointer;
      transition: all 0.15s var(--ease);
      white-space: nowrap;
    }

    .btn-login:hover {
      background: var(--cyan);
      color: #04121a;
    }

    .btn-logout {
      font-family: var(--font-mono);
      font-size: 0.7rem;
      padding: 6px 12px;
      border-radius: 8px;
      border: 1px solid var(--border);
      background: transparent;
      color: var(--text-secondary);
      cursor: pointer;
      transition: all 0.15s var(--ease);
    }

    .btn-logout:hover {
      border-color: var(--red);
      color: var(--red);
    }

    .modal-backdrop {
      position: fixed;
      inset: 0;
      z-index: 300;
      display: none;
      align-items: center;
      justify-content: center;
      padding: 24px;
      background: rgba(2, 6, 16, 0.8);
      backdrop-filter: blur(6px);
    }

    .modal-backdrop.open { display: flex; }

    .modal {
      background: var(--bg-panel);
      border: 1px solid var(--border-hover);
      border-radius: 16px;
      padding: 30px 28px;
      max-width: 460px;
      width: 100%;
      text-align: center;
      box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
      animation: panelIn 0.2s var(--ease);
    }

    .modal h3 {
      font-size: 1.05rem;
      margin-bottom: 8px;
      color: var(--text-primary);
    }

    .modal p {
      font-size: 0.85rem;
      line-height: 1.6;
      color: var(--text-secondary);
      margin-bottom: 18px;
    }

    .login-code {
      font-family: var(--font-mono);
      font-size: 1.9rem;
      font-weight: 600;
      letter-spacing: 0.3em;
      color: var(--cyan);
      text-shadow: 0 0 18px var(--cyan-glow);
      padding: 14px 0 14px 0.3em;
      margin-bottom: 6px;
      border: 1px dashed var(--border-hover);
      border-radius: 12px;
      background: rgba(0, 212, 255, 0.04);
    }

    .login-hint {
      font-size: 0.72rem;
      color: var(--text-tertiary);
      margin-bottom: 20px;
      font-family: var(--font-mono);
    }

    .login-open {
      display: inline-block;
      font-family: var(--font-sans);
      font-size: 0.9rem;
      font-weight: 600;
      padding: 12px 26px;
      border-radius: 10px;
      background: var(--cyan);
      color: #04121a;
      text-decoration: none;
      transition: filter 0.15s var(--ease);
    }

    .login-open:hover { filter: brightness(1.12); }

    /* Selettore del bot: compare solo quando i bot raggiungibili sono piu' di
       uno. Con tre assistenti dietro lo stesso indirizzo, sapere con quale si
       sta parlando non e' un dettaglio: e' la differenza fra due memorie. */
    .bot-pick {
      display: flex;
      flex-direction: column;
      gap: 8px;
      margin-bottom: 20px;
    }

    .bot-pick button {
      font-family: var(--font-sans);
      font-size: 0.92rem;
      font-weight: 600;
      padding: 13px 18px;
      border-radius: 10px;
      border: 1px solid var(--border);
      background: var(--bg-card);
      color: var(--text-primary);
      cursor: pointer;
      transition: all 0.15s var(--ease);
    }

    .bot-pick button:hover {
      border-color: var(--cyan);
      color: var(--cyan);
      background: rgba(0, 212, 255, 0.06);
    }

    .bot-switch {
      background: none;
      border: none;
      color: var(--text-tertiary);
      font-family: var(--font-mono);
      font-size: 0.72rem;
      cursor: pointer;
      text-decoration: underline;
      padding: 0;
      margin-top: 4px;
    }

    .bot-switch:hover { color: var(--cyan); }

    /* Il bot connesso, in header. */
    .who-bot {
      font-family: var(--font-mono);
      font-size: 0.72rem;
      color: var(--cyan);
      white-space: nowrap;
    }

    .login-status {
      margin-top: 18px;
      font-family: var(--font-mono);
      font-size: 0.74rem;
      color: var(--text-secondary);
      min-height: 1.2em;
    }

    .login-status.err { color: var(--red); }
    .login-status.ok { color: var(--green); }

    .modal-close {
      margin-top: 14px;
      background: none;
      border: none;
      color: var(--text-tertiary);
      font-family: var(--font-mono);
      font-size: 0.72rem;
      cursor: pointer;
    }

    .modal-close:hover { color: var(--text-secondary); }

    /* Card generica dei pannelli. Non si puo' riusare .mkt-card: e' definita
       sotto #section-marketing e fuori da quella sezione non applica nulla. */
    .panel-card {
      background: var(--bg-card);
      border: 1px solid var(--border);
      border-radius: 14px;
      padding: 20px;
    }

    .panel-card-title {
      font-family: var(--font-mono);
      font-size: 0.7rem;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: var(--text-secondary);
      margin-bottom: 10px;
    }

    /* Riquadro "serve il login" dentro i pannelli, al posto dei due gate separati */
    .locked {
      border: 1px dashed var(--border-hover);
      border-radius: 14px;
      padding: 26px;
      text-align: center;
      background: rgba(0, 212, 255, 0.03);
    }

    .locked p {
      font-size: 0.85rem;
      color: var(--text-secondary);
      margin-bottom: 16px;
      line-height: 1.6;
    }

    /* ========================================
       RESPONSIVE
       ======================================== */
    @media (max-width: 1024px) {
      .hvitals {
        gap: 14px;
      }
      .capabilities, .wiki-grid {
        grid-template-columns: repeat(2, 1fr);
      }
      .vitals {
        grid-template-columns: repeat(2, 1fr);
      }
      .arch-flow {
        grid-template-columns: 1fr;
        gap: 12px;
      }
      .arch-arrow {
        transform: rotate(90deg);
      }
      .soul-traits {
        grid-template-columns: repeat(2, 1fr);
      }
    }

    /* Sotto questa soglia la conversazione non ha piu' larghezza per reggere
       una colonna a fianco: lo stesso nodo torna una striscia orizzontale
       sopra il composer, scorrevole. Nessun contenuto cambia, cambia il posto. */
    @media (max-width: 1100px) {
      .panel-chat .chat-shell {
        display: flex;
        flex-direction: column;
      }
      .panel-chat .chat-log { flex: 1; min-height: 0; max-height: none; }
      .panel-chat .chat-composer,
      .panel-chat .chat-meta,
      .panel-chat .doc-bar,
      .panel-chat .alle-zona,
      .panel-chat .chat-activity { flex-shrink: 0; }
      .panel-chat .chat-activity {
        border-left: 0; border-top: 1px solid var(--border);
        /* Niente scroll: qui e' un'informazione di STATO, non un pannello.
           Una striscia alta due righe che scrolla, con un bottone tagliato a
           meta' dal bordo, e' peggio di una striscia che dice meno. */
        max-height: none; overflow: hidden;
        padding: 9px 20px;
      }
      .att-titolo { display: none; }
      /* La striscia mostra lo stato, non lo spiega: durante un turno resta
         solo l'ultima riga del registro, cioe' l'informazione piu' fresca —
         "passo 2/8" e poi "⚙ document_search…" che lo sostituisce. La
         spiegazione vive nella colonna, dove c'e' spazio. */
      .att-riga:not(:last-child) { display: none; }
      /* Da sloggati non puo' esistere nessun turno; da fermi non ne sta
         girando uno. In tutti e due i casi, su schermo stretto, la striscia
         ruberebbe righe al contenuto per non dire niente: sparisce.
         Sul desktop la colonna resta — li' lo spazio c'e', la frase spiega a
         cosa serve, e a turno finito conserva il registro dei passi, che
         /api/chat/history non restituisce.
         L'ECCEZIONE e' il turno orfano: se hai ricaricato a meta' turno la
         striscia RIcompare, perche' li' ha qualcosa da dirti. Vedi
         attivitaIdle(), che resta il suo unico posto. */
      .panel-chat .chat-activity.senza-turni,
      .panel-chat .chat-activity.a-riposo { display: none; }
      /* Qui stavano due regole che nascondevano il secondo paragrafo e il
         bottone di .att-vuota. Sono morte: quei nodi entrano nel DOM solo se
         turnoRimastoAperto() e' vero, cioe' solo quando la striscia e'
         visibile — nell'altro ramo non c'e' niente da nascondere, perche'
         sparisce la striscia intera. Nel caso orfano li vogliamo tutti,
         margini compresi: e' l'unico momento in cui hanno da dire qualcosa.
         Il blocco si prende la sua altezza (flex-shrink: 0) e a stringersi e'
         .chat-log, che ha flex:1 e min-height:0 — nessun taglio. */

      /* L'header e' stretto gia' qui, non a 1024: la sidebar a 210px gli ha
         tolto 138px. Il pallino colorato resta e dice online/offline da solo. */
      #status-text { display: none; }
      .status-badge { padding: 6px 10px; }
    }

    @media (max-width: 768px) {
      :root {
        --sidebar-width: 0px;
      }
      /* La sidebar diventa una barra in basso invece di sparire. Con i pannelli
         al posto dello scroll, nasconderla lasciava il telefono senza NESSUN
         modo di uscire dalla chat. */
      .sidebar {
        flex-direction: row;
        justify-content: center;
        top: auto;
        bottom: 0;
        left: 0;
        right: 0;
        width: 100%;
        height: 58px;
        padding: 0 8px;
        border-right: none;
        border-top: 1px solid var(--border);
        z-index: 120;
      }
      .sidebar-logo {
        display: none;
      }
      /* La barra in basso e' touch e non ha larghezza per le etichette:
         torna a sole icone, com'era. Non un terzo comportamento. */
      .nav-group, .nav-item .label {
        display: none;
      }
      .nav-item {
        width: 56px;
        justify-content: center;
        padding: 0;
      }
      .nav-item.active::before { display: none; }
      .sidebar-nav {
        flex-direction: row;
        gap: 4px;
        overflow-x: auto;
        overflow-y: hidden;
        width: 100%;
        justify-content: space-around;
        /* La centratura verticale arrivava da `align-items: center` su .sidebar,
           tolto perche' a colonna schiacciava le voci a larghezza contenuto.
           Qui va rimessa, o le icone si appoggiano al bordo alto della barra. */
        align-items: center;
        padding: 0;
      }
      .main {
        padding-bottom: 58px;
      }
      .panel {
        /* 88px = i 30 di prima + i 58 della barra di navigazione, che qui e'
           position:fixed e copre l'ultima fascia di schermo. Il padding sta
           sul contenitore che SCROLLA, che e' l'unico posto che garantisce di
           poter arrivare in fondo: senza, l'ultimo campo di un modulo lungo
           resta sotto la barra e non lo raggiungi.
           (Il pannello chat non scrolla e ha il suo padding, qui sotto.)

           CAUSA NON ISOLATA — leggere prima di togliere righe.
           `.main { padding-bottom: 58px }` qui sotto dovrebbe gia' bastare, e
           sulla CHAT funziona: sotto la shell il vuoto si vede. Sul pannello
           marketing no, e lo scroll finiva sotto la barra. Non e' stato
           possibile riprodurre la differenza senza un dispositivo, quindi la
           correzione e' messa dove funziona per costruzione invece di
           inseguire la causa.
           IL SEGNALE: se in fondo a un pannello lungo compaiono ~58px di
           vuoto in piu' del previsto, allora agiscono entrambe le regole e
           una va tolta — questa, non quella su .main. Se il vuoto non c'e',
           .main non stava agendo sui pannelli che scrollano e questa riga e'
           l'unica che tiene: non toccarla. */
        padding: 18px 16px 88px;
      }
      .panel.panel-chat {
        padding: 12px 14px;
      }
      .capabilities, .wiki-grid {
        grid-template-columns: 1fr;
      }
      .vitals {
        grid-template-columns: repeat(2, 1fr);
      }
      .header {
        padding: 0 16px;
      }
      /* In header resta il minimo indispensabile: marchio e accesso. */
      .hvitals, .header-sub {
        display: none;
      }
      .footer {
        display: none;
      }
      .soul-traits {
        grid-template-columns: 1fr 1fr;
      }
      .boot-title {
        font-size: 1.5rem;
      }
    }

    /* ========================================
       UTILITY / ANIMATION HELPERS
       ======================================== */
    /* Counter animation */
    @keyframes count-up {
      from { opacity: 0; transform: translateY(10px); }
      to { opacity: 1; transform: translateY(0); }
    }

    /* ═══════════════════════════════════════════════════════════════
       CHAT — Command Interface
       ═══════════════════════════════════════════════════════════════ */

    .chat-shell {
      background: linear-gradient(180deg, rgba(13, 21, 37, 0.85), rgba(8, 14, 28, 0.95));
      border: 1px solid var(--border);
      border-radius: 18px;
      overflow: hidden;
      position: relative;
      box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.03);
    }
    /* filo di luce sul bordo superiore: firma visiva del pannello attivo */
    .chat-shell::before {
      content: '';
      position: absolute; top: 0; left: 8%; right: 8%; height: 1px;
      background: linear-gradient(90deg, transparent, var(--cyan-glow) 20%, var(--cyan) 50%, var(--cyan-glow) 80%, transparent);
      opacity: .65;
    }

    .chat-log {
      max-height: 62vh;
      min-height: 220px;
      overflow-y: auto;
      overflow-x: hidden;
      padding: 24px 22px 8px;
      scroll-behavior: smooth;
      scrollbar-width: thin;
      scrollbar-color: var(--border-hover) transparent;
    }
    .chat-log::-webkit-scrollbar { width: 8px; }
    .chat-log::-webkit-scrollbar-thumb { background: var(--border-hover); border-radius: 4px; }

    .chat-empty {
      text-align: center;
      padding: 42px 20px 48px;
      color: var(--text-secondary);
    }
    .chat-empty-ico { font-size: 30px; opacity: .5; margin-bottom: 14px; }
    .chat-empty h3 {
      font-size: 15px; font-weight: 600; color: var(--text-primary);
      margin-bottom: 8px; letter-spacing: .01em;
    }
    .chat-empty p { font-size: 13px; line-height: 1.6; max-width: 460px; margin: 0 auto; }
    .chat-suggests { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 20px; }
    .chat-suggest {
      background: rgba(0, 212, 255, .06);
      border: 1px solid var(--border);
      color: var(--text-primary);
      border-radius: 999px;
      padding: 7px 15px;
      font-size: 12.5px;
      font-family: var(--font-sans);
      cursor: pointer;
      transition: all .18s var(--ease);
    }
    .chat-suggest:hover {
      border-color: var(--border-hover);
      background: rgba(0, 212, 255, .12);
      transform: translateY(-1px);
    }

    /* ── messaggi ── */
    .msg { display: flex; gap: 12px; margin-bottom: 22px; animation: msgIn .32s var(--ease); }
    @keyframes msgIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

    .msg-avatar {
      flex: 0 0 30px; height: 30px; border-radius: 9px;
      display: grid; place-items: center;
      font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
      letter-spacing: .04em; margin-top: 2px;
    }
    .msg.user .msg-avatar { background: rgba(240, 180, 41, .12); color: var(--gold); border: 1px solid var(--gold-dim); }
    .msg.bot .msg-avatar { background: rgba(0, 212, 255, .1); color: var(--cyan); border: 1px solid var(--border-hover); }

    .msg-body { flex: 1; min-width: 0; }
    .msg-role {
      font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text-tertiary); margin-bottom: 6px;
    }
    .msg-text {
      font-size: 14.5px; line-height: 1.68; color: var(--text-primary);
      word-wrap: break-word; overflow-wrap: break-word;
    }
    .msg.user .msg-text {
      background: rgba(240, 180, 41, .05);
      border-left: 2px solid var(--gold-dim);
      padding: 10px 14px; border-radius: 0 10px 10px 0;
    }
    .msg-text strong { color: #fff; font-weight: 600; }
    .msg-text a { color: var(--cyan); text-decoration: none; border-bottom: 1px solid var(--cyan-dim); }
    .msg-text a:hover { border-bottom-color: var(--cyan); }
    .chat-ul { margin: 8px 0 8px 4px; padding-left: 18px; }
    .chat-ul li { margin-bottom: 5px; }
    .chat-code {
      font-family: var(--font-mono); font-size: 12.5px;
      background: rgba(0, 212, 255, .08); border: 1px solid var(--border);
      padding: 1px 6px; border-radius: 5px; color: var(--cyan);
    }
    .chat-pre {
      background: #050a14; border: 1px solid var(--border);
      border-radius: 10px; padding: 14px 16px; margin: 12px 0;
      overflow-x: auto; position: relative;
    }
    .chat-pre code { font-family: var(--font-mono); font-size: 12.5px; line-height: 1.6; color: #a8e6ff; }
    .chat-pre[data-lang]::after {
      content: attr(data-lang);
      position: absolute; top: 8px; right: 12px;
      font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .1em;
      text-transform: uppercase; color: var(--text-tertiary);
    }

    /* ── card documento: la risposta a "un visual per i documenti" ── */
    .chat-doc {
      display: flex; align-items: center; gap: 13px;
      background: rgba(0, 212, 255, .04);
      border: 1px solid var(--border);
      border-radius: 12px; padding: 12px 14px; margin: 12px 0;
      text-decoration: none !important; border-bottom: 1px solid var(--border) !important;
      transition: all .2s var(--ease);
    }
    .chat-doc:hover {
      border-color: var(--border-hover) !important;
      background: rgba(0, 212, 255, .08);
      transform: translateX(2px);
    }
    .chat-doc-ico {
      flex: 0 0 36px; height: 36px; border-radius: 9px;
      background: rgba(0, 212, 255, .1); border: 1px solid var(--border-hover);
      display: grid; place-items: center; font-size: 17px;
    }
    .chat-doc[data-icon="doc"] .chat-doc-ico::before { content: '📄'; }
    .chat-doc[data-icon="sheet"] .chat-doc-ico::before { content: '📊'; }
    .chat-doc[data-icon="slide"] .chat-doc-ico::before { content: '🖼'; }
    .chat-doc[data-icon="drive"] .chat-doc-ico::before { content: '🗂'; }
    .chat-doc[data-icon="cal"] .chat-doc-ico::before { content: '📅'; }
    .chat-doc[data-icon="mail"] .chat-doc-ico::before { content: '✉️'; }
    .chat-doc-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
    /* Su una riga con i puntini: da quando la card porta il TITOLO del documento e
       non la parola "Documento", quel testo arriva dal modello e non ha un tetto —
       "Tappeti logo personalizzati: mappa concorrenti, modelli di vendita e prezzi
       pubblici" sono 88 caratteri, che a capo trasformerebbero una card in un
       paragrafo. Il troncamento regge perche' .chat-doc-body ha min-width:0. */
    .chat-doc-kind {
      font-size: 13.5px; font-weight: 600; color: var(--text-primary);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .chat-doc-host { font-family: var(--font-mono); font-size: 11px; color: var(--text-secondary); }
    .chat-doc-open {
      margin-left: auto; font-family: var(--font-mono); font-size: 10px;
      letter-spacing: .1em; text-transform: uppercase; color: var(--cyan);
      border: 1px solid var(--border-hover); border-radius: 6px; padding: 4px 9px;
    }

    /* ── anteprima immagine ── */
    .chat-img {
      display: block; margin: 12px 0; border-radius: 12px; overflow: hidden;
      border: 1px solid var(--border) !important; max-width: 420px;
      transition: all .25s var(--ease);
    }
    .chat-img:hover { border-color: var(--border-hover) !important; transform: scale(1.01); }
    .chat-img img { display: block; width: 100%; height: auto; }

    /* ── footer del messaggio: passi, tool, costo ── */
    .msg-foot {
      display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
      margin-top: 12px; font-family: var(--font-mono); font-size: 10.5px;
      color: var(--text-tertiary);
    }
    .msg-foot .dot { opacity: .4; }
    .msg-cost { color: var(--gold); }
    .msg-badge {
      border: 1px solid var(--gold-dim); color: var(--gold);
      border-radius: 5px; padding: 2px 7px; letter-spacing: .06em; text-transform: uppercase;
    }
    /* "dettagli ▾": esiste solo sotto i 768, dove il riepilogo occupa due o tre
       righe sotto OGNI risposta. Sul desktop lo spazio c'e' e il costo visibile
       e' il rate limiter piu' economico che esista, quindi resta scoperto.
       Lo stato sta in una classe e le regole che nascondono vivono dentro il
       media query: allargando la finestra tutto ricompare da solo, senza
       listener sul resize e senza <details> da riaprire. */
    .msg-det { display: none; }

    /* ── le tre azioni sotto una risposta ── */
    .msg-azioni { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 11px; }
    /* Il colore e lo sfondo NON sono valori nuovi: --text-secondary e' quello
       delle altre due azioni discrete in mono di questa pagina (.att-vuota
       button e .chat-meta button), e il velo di ciano viene da .chat-suggest,
       che e' la pillola premibile discreta gia' esistente.
       Prima qui c'era --text-tertiary, cioe' il colore del testo PASSIVO —
       .msg-foot, il contenitore .chat-meta, .att-riga.fine. Nessun elemento
       premibile lo usa, ed era il difetto: tre bottoni dipinti col colore dei
       metadati che hanno intorno. Alpha da 0.2 a 0.4 e' lo stesso raddoppio
       che rende "ricarica" leggibile come azione accanto al testo spento.
       Lo sfondo serve alla FORMA: --border e' alpha 0.1 e con luce ambientale
       il bordo da solo sparisce, quindi non sembrerebbero premibili. */
    .msg-azioni button {
      background: rgba(0, 212, 255, .06);
      border: 1px solid var(--border); border-radius: 6px;
      color: var(--text-secondary); font-family: var(--font-mono);
      font-size: 10px; letter-spacing: .06em; padding: 4px 10px;
      cursor: pointer; transition: all .18s var(--ease);
    }
    .msg-azioni button:hover { border-color: var(--border-hover); color: var(--cyan); }

    /* .tool-chips e' il contenitore VIVO, durante il turno. A turno finito i
       chip vengono spostati dentro .msg-foot e questo contenitore sparisce. */
    .tool-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
    .msg-foot .tool-chip { font-size: 10px; padding: 3px 8px; }
    .tool-chip {
      display: inline-flex; align-items: center; gap: 6px;
      font-family: var(--font-mono); font-size: 10.5px;
      background: rgba(255, 255, 255, .02); border: 1px solid var(--border);
      border-radius: 6px; padding: 4px 9px; color: var(--text-secondary);
    }
    .tool-chip.ok { border-color: var(--green-dim); color: var(--green); }
    .tool-chip.ko { border-color: rgba(255, 59, 59, .3); color: var(--red); }
    .tool-chip.run { border-color: var(--border-hover); color: var(--cyan); }
    /* Il quarto stato: lo strumento e' partito e il suo tool_end non e' mai
       arrivato, perche' il turno si e' fermato prima. Non e' .ok e non e' .ko
       — quelli affermano un esito, e qui l'esito non lo sappiamo. Spento e
       fermo, col trattino al posto del segno: e' la stessa resa che la pagina
       usa per un numero che non ha (il "—" dei riquadri in Command Center).
       L'assenza di informazione si mostra, non si sostituisce. */
    .tool-chip.cut {
      border-style: dashed; border-color: var(--border);
      color: var(--text-tertiary);
    }
    /* Stessa famiglia di .tool-chip.cut, e per la stessa ragione: qui dentro non
       c'e' nessun rosso, di proposito. Il rosso dice "guasto"; questo stato dice
       "il turno gira e non lo sto guardando", che e' un'altra cosa e non e'
       colpa di nessuno. La versione .chiusa e' spenta come i chip troncati:
       abbiamo smesso di seguire, non sappiamo com'e' finito. */
    .attesa {
      display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
      font-family: var(--font-mono); font-size: 12px; color: var(--text-secondary);
    }
    .attesa.chiusa { color: var(--text-tertiary); }
    .attesa-ricarica {
      font-family: var(--font-mono); font-size: 10px;
      background: none; border: 1px solid var(--border); border-radius: 6px;
      color: var(--text-secondary); padding: 4px 9px; cursor: pointer;
    }
    .attesa-ricarica:hover { border-color: var(--border-hover); color: var(--cyan); }
    .tool-chip.run::before {
      content: ''; width: 5px; height: 5px; border-radius: 50%;
      background: var(--cyan); animation: chipPulse 1s ease-in-out infinite;
    }
    @keyframes chipPulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

    /* ── stato "sta pensando" ── */
    .thinking { display: flex; align-items: center; gap: 10px; color: var(--cyan); font-size: 13.5px; }
    .thinking-orb {
      width: 9px; height: 9px; border-radius: 50%; background: var(--cyan);
      box-shadow: 0 0 12px var(--cyan-glow); animation: orb 1.4s ease-in-out infinite;
    }
    @keyframes orb {
      0%, 100% { transform: scale(1); opacity: 1; }
      50% { transform: scale(1.5); opacity: .45; }
    }
    .thinking-step { font-family: var(--font-mono); font-size: 11px; color: var(--text-secondary); }

    .chat-activity {
      min-height: 0; padding: 0 22px; overflow: hidden;
      font-family: var(--font-mono); font-size: 11px; color: var(--text-secondary);
      transition: min-height .2s var(--ease), padding .2s var(--ease);
    }
    .att-titolo {
      font-size: 9px; letter-spacing: .18em; text-transform: uppercase;
      color: var(--text-tertiary); padding-bottom: 10px; margin-bottom: 10px;
      border-bottom: 1px solid var(--border);
    }
    .att-riga { padding: 3px 0; line-height: 1.5; color: var(--text-secondary); }
    .att-riga.run { color: var(--cyan); }
    .att-riga.ok  { color: var(--green); }
    .att-riga.ko  { color: var(--red); }
    /* Stessa famiglia di .tool-chip.cut: spento, perche' non sappiamo com'e'
       finito — sappiamo di aver smesso di guardare. */
    .att-riga.cut  { color: var(--text-tertiary); }
    .att-riga.fine { color: var(--text-tertiary); padding-top: 8px; }
    .att-vuota p {
      font-family: var(--font-sans); font-size: 11.5px; line-height: 1.6;
      color: var(--text-tertiary); margin-bottom: 11px;
    }
    .att-vuota button {
      font-family: var(--font-mono); font-size: 10px;
      background: none; border: 1px solid var(--border); border-radius: 6px;
      color: var(--text-secondary); padding: 5px 10px; cursor: pointer;
    }
    .att-vuota button:hover { border-color: var(--border-hover); color: var(--cyan); }

    /* ── composer ── */
    .chat-composer {
      display: flex; align-items: flex-end; gap: 12px;
      padding: 14px 18px; border-top: 1px solid var(--border);
      background: rgba(5, 10, 20, .6);
    }
    .chat-prompt {
      font-family: var(--font-mono); font-size: 12.5px; color: var(--cyan);
      white-space: nowrap; padding-bottom: 9px; text-shadow: 0 0 10px var(--cyan-glow);
    }
    #chat-input {
      flex: 1; min-width: 0; background: transparent; border: none; resize: none;
      color: var(--text-primary); font-family: var(--font-sans);
      /* 16px: sotto questa soglia iOS zooma al focus e la pagina "salta" */
      font-size: 16px; line-height: 1.55; padding: 8px 0; max-height: 148px;
      outline: none;
    }
    #chat-input::placeholder { color: var(--text-tertiary); }
    .chat-send {
      flex: 0 0 auto; background: var(--cyan); color: #04121a;
      border: none; border-radius: 10px; padding: 9px 17px;
      font-family: var(--font-sans); font-size: 13.5px; font-weight: 600;
      cursor: pointer; transition: all .18s var(--ease);
    }
    .chat-send:hover:not(:disabled) { filter: brightness(1.14); box-shadow: 0 0 20px var(--cyan-glow); }
    .chat-send:disabled { opacity: .35; cursor: not-allowed; }
    .chat-send.stop { background: transparent; color: var(--red); border: 1px solid rgba(255, 59, 59, .4); }

    /* ── gli allegati ─────────────────────────────────────────────────
       Fascia fra il composer e la barra documento. Il prefisso e' `alle-` e non
       `att-`: quello e' gia' della colonna delle attivita' (.att-riga,
       .att-titolo, e perfino .att-riga.ko in rosso), e due funzioni diverse
       sulle stesse regole divergono al primo ritocco. */
    .alle-zona {
      border-top: 1px solid var(--border);
      background: rgba(5, 10, 20, .35);
    }
    .alle-riga {
      display: flex; flex-wrap: wrap; gap: 8px;
      padding: 10px 20px 0;
    }
    .alle-riga:empty { display: none; }

    .alle-card {
      display: flex; align-items: center; gap: 9px;
      border: 1px solid var(--border-hover); border-radius: 8px;
      background: rgba(255, 255, 255, .025);
      padding: 6px 8px; max-width: 250px; position: relative; overflow: hidden;
    }
    /* Lo scarto RESTA a schermo. Sparire in silenzio e' la versione peggiore:
       chi trascina cinque file e ne vede quattro pensa di aver sbagliato mira,
       non di aver superato un limite. Non esiste una classe rossa riusabile nel
       foglio — .login-status.err e .tool-chip.ko sono altre cose — quindi
       questa e' nuova, sullo stesso pattern. */
    .alle-card.ko { border-color: rgba(255, 59, 59, .45); background: rgba(255, 59, 59, .06); }

    .alle-thumb {
      width: 34px; height: 34px; flex: none; border-radius: 6px;
      background: linear-gradient(135deg, rgba(0, 212, 255, .18), rgba(13, 21, 37, .9));
      border: 1px solid var(--border);
      display: flex; align-items: center; justify-content: center;
      font-family: var(--font-mono); font-size: 8.5px; letter-spacing: .06em;
      color: var(--text-secondary); text-transform: uppercase; overflow: hidden;
    }
    .alle-thumb img { width: 100%; height: 100%; object-fit: cover; }

    .alle-meta { min-width: 0; }
    .alle-nome {
      font-size: 12.5px; color: var(--text-primary);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .alle-sub { font-family: var(--font-mono); font-size: 10px; color: var(--text-secondary); }
    .alle-card.ko .alle-sub { color: var(--red); white-space: normal; font-family: var(--font-sans); font-size: 11.5px; }
    .alle-x {
      background: none; border: none; color: var(--text-secondary);
      cursor: pointer; font-size: 15px; line-height: 1; padding: 2px 4px; margin-left: auto;
    }
    .alle-x:hover { color: var(--text-primary); }
    .alle-prog {
      position: absolute; left: 0; bottom: 0; height: 2px;
      background: var(--cyan); transition: width .18s var(--ease);
    }

    .alle-barra {
      display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
      padding: 9px 20px 10px;
    }
    .alle-btn {
      display: inline-flex; align-items: center; gap: 6px;
      background: none; border: 1px solid var(--border-hover); border-radius: 7px;
      color: var(--text-secondary); font-family: var(--font-mono);
      font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
      padding: 5px 10px; cursor: pointer; transition: all .18s var(--ease);
    }
    .alle-btn:hover:not(:disabled) { border-color: var(--cyan); color: var(--text-primary); }
    .alle-btn:disabled { opacity: .4; cursor: not-allowed; }
    .alle-clip { width: 13px; height: 13px; flex: none; }
    .alle-hint { font-size: 12px; color: var(--text-tertiary); }
    .alle-hint kbd {
      font-family: var(--font-mono); font-size: 10.5px;
      border: 1px solid var(--border-hover); border-radius: 4px;
      padding: 1px 5px; color: var(--text-secondary);
    }
    .alle-conta {
      margin-left: auto; font-family: var(--font-mono);
      font-size: 10px; color: var(--text-tertiary);
    }
    .alle-conta.pieno { color: var(--gold); }

    /* Il bersaglio del trascinamento e' TUTTA l'area conversazione, non la
       barra: puntare una striscia alta trenta pixel col mouse carico e' un
       gesto di precisione chiesto senza motivo. */
    .chat-log.alle-drop {
      outline: 1px dashed var(--cyan);
      outline-offset: -6px;
      background: rgba(0, 212, 255, .04);
    }

    /* Le miniature nella bolla gia' mandata, col "riusa". Vivono SOLO nella
       pagina aperta: dopo un reload restano il marcatore testuale e nessun
       riuso — limite dichiarato, non guasto. */
    .alle-inviati { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
    .alle-riusa {
      display: inline-flex; align-items: center; gap: 6px;
      border: 1px solid var(--border); border-radius: 999px;
      background: rgba(255, 255, 255, .02);
      color: var(--text-secondary); font-size: 11.5px;
      padding: 3px 10px; cursor: pointer; transition: all .18s var(--ease);
    }
    .alle-riusa:hover { border-color: var(--cyan); color: var(--text-primary); }

    /* ── la barra di stile documento ──────────────────────────────────
       Fascia fra il composer e la riga di stato, con lo stesso bordo: nel mockup
       stava dentro il riquadro del composer, ma qui il composer non e' una card —
       e' una fascia a piena larghezza, e questa e' la fascia sotto.
       Mono 10px come .chat-meta, che e' il riferimento giusto: sono comandi
       secondari della stessa zona, non bottoni principali. */
    .doc-bar {
      border-top: 1px solid var(--border);
      background: rgba(5, 10, 20, .45);
    }
    .doc-head { display: flex; align-items: center; gap: 11px; padding: 8px 20px; }
    .doc-sum {
      display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
      background: none; border: 1px solid var(--border); border-radius: 6px;
      color: var(--text-secondary); cursor: pointer;
      font-family: var(--font-mono); font-size: 10px; letter-spacing: .06em;
      padding: 5px 11px; transition: all .15s var(--ease);
    }
    .doc-sum:hover { border-color: var(--border-hover); color: var(--text-primary); }
    .doc-sum.aperto, .doc-sum.scelto { border-color: var(--cyan); color: var(--cyan); }
    /* Lo swatch non e' decorazione: gli identificatori sono NEUTRI (linea-2 non si
       legge come un marchio) e il colore e' l'unico indizio riconoscibile. */
    .doc-sw {
      width: 11px; height: 11px; border-radius: 3px; flex: none;
      box-shadow: 0 0 0 1px rgba(255, 255, 255, .16);
    }
    /* Il buco dichiarato: vuoto e tratteggiato. Nessun colore approssimato. */
    .doc-sw.vuoto { background: transparent; box-shadow: none; border: 1px dashed var(--text-tertiary); }
    .doc-hint { font-size: 11.5px; color: var(--text-tertiary); min-width: 0; }
    .doc-hint.avviso { color: var(--gold); }

    .doc-tray { border-top: 1px solid var(--border); padding: 11px 20px 13px; }
    .doc-tray[hidden] { display: none; }
    .doc-row { display: flex; align-items: center; gap: 10px; }
    .doc-row + .doc-row { margin-top: 9px; }
    .doc-k {
      font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .16em;
      color: var(--text-tertiary); width: 74px; flex: none;
    }
    .doc-chips { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
    .doc-chip {
      display: flex; align-items: center; gap: 7px;
      background: none; border: 1px solid var(--border); border-radius: 6px;
      color: var(--text-secondary); cursor: pointer;
      font-family: var(--font-sans); font-size: 12px;
      padding: 5px 10px; transition: all .15s var(--ease);
    }
    .doc-chip:hover { border-color: var(--border-hover); color: var(--text-primary); }
    .doc-chip[aria-pressed="true"] {
      border-color: var(--cyan); color: var(--cyan); background: var(--cyan-dim);
    }
    .doc-chip.senza-colore { border-style: dashed; color: var(--text-tertiary); }
    /* Riga inerte: senza formato non c'e' nessun documento da colorare. Le chip
       restano premibili e rispondono con la ragione — un click che non fa NIENTE
       sarebbe lo stato nascosto che questa barra esiste per evitare. */
    .doc-row.inerte { opacity: .45; }

    .chat-meta {
      display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
      padding: 9px 20px; border-top: 1px solid var(--border);
      font-family: var(--font-mono); font-size: 10px; letter-spacing: .04em;
      color: var(--text-tertiary); background: rgba(5, 10, 20, .35);
    }
    .chat-meta button {
      background: none; border: none; color: var(--text-secondary);
      font-family: var(--font-mono); font-size: 10px; cursor: pointer;
      text-decoration: underline; text-underline-offset: 2px;
    }
    .chat-meta button:hover { color: var(--cyan); }

    /* ── gate (disabilitata / login) ── */
    .chat-gate {
      background: var(--bg-card); border: 1px solid var(--border);
      border-radius: 18px; padding: 40px 32px; text-align: center;
    }
    .chat-gate-ico { font-size: 26px; opacity: .55; margin-bottom: 14px; }
    .chat-gate h3 { font-size: 16px; font-weight: 600; color: var(--text-primary); margin-bottom: 9px; }
    .chat-gate p {
      font-size: 13px; line-height: 1.65; color: var(--text-secondary);
      max-width: 470px; margin: 0 auto 18px;
    }
    .chat-gate code {
      font-family: var(--font-mono); font-size: 12px; color: var(--gold);
      background: var(--gold-dim); padding: 2px 6px; border-radius: 4px;
    }

    @media (max-width: 768px) {
      .chat-log { max-height: 54vh; padding: 18px 14px 6px; }

      /* Il riepilogo dietro un tocco. Il combinatore > prende solo gli ELEMENTI:
         i .msg-foot dell'errore e dello Stop scrivono con textContent, quindi
         non hanno figli elemento e restano interi — li' non c'e' niente da
         collassare e "dettagli" non compare, perche' quel foot non lo riceve. */
      .msg-det {
        display: inline; cursor: pointer;
        text-decoration: underline; text-underline-offset: 2px;
      }
      .msg-foot > *:not(.msg-det) { display: none; }
      .msg-foot.aperto > * { display: inline-flex; }
      /* I tre bottoni su UNA riga, e il bersaglio piu' alto di prima.
         Andavano a capo perche' a 390px il corpo del messaggio ha ~295px
         (390 meno i 14+14 del pannello, i 14+14 del registro, i 30
         dell'avatar e i 9 del gap) e i tre a 11px con 14 di padding ne
         chiedevano ~291: al limite, quindi "condividi" scendeva.

         Il padding VERTICALE non c'entra con l'andare a capo. Quindi si
         stringe in orizzontale — font e padding tornano ai valori base, che
         sono quelli di .chat-meta, cioe' il riferimento giusto: sono azioni
         secondarie sotto ogni risposta, non bottoni principali — e insieme
         si ALZA il bersaglio, da ~34px a ~39px.

         Il conto torna a ~258px su ~295, con margine.
         Una riga da 39px costa comunque meno delle due da 34 di prima.
         Se sul dispositivo vero andasse ancora a capo, la mossa non e'
         stringere ancora: e' due per riga invece di uno e due. Meglio due
         righe pulite che bersagli che si sbagliano. */
      .msg-azioni { gap: 6px; }
      .msg-azioni button { padding: 12px 10px; }
      .chat-composer { padding: 11px 13px; }
      .chat-prompt { display: none; }
      .chat-img { max-width: 100%; }
      .msg { gap: 9px; }

      /* Il titolo di sezione sparisce SOLO qui, e solo sulla chat: e' l'unico
         pannello con l'altezza a budget fisso (.chat-shell e' flex:1 dentro un
         pannello che non scrolla), quindi la riga la paghi in messaggi. Sugli
         altri pannelli lo scroll la rende gratis — e li' il titolo e' l'unico
         appiglio testuale, perche' la barra in basso e' a sole icone
         (.nav-item .label sparisce piu' sopra) e "Architettura" e "Carattere"
         si distinguono solo da quello. Nella chat no: composer e messaggi
         dicono da soli dove sei. */
      .panel-chat .section-header { display: none; }

      /* La riga di stato su UNA riga. Via l'id numerico e il suo separatore:
         nove cifre su cui non agisci. L'identita' che conta non sparisce —
         #who-bot in header scrive "● <nome bot>" quando i backend sono piu'
         d'uno, e qui sopra si nascondono solo .hvitals e .header-sub. "Sei
         connesso" lo dicono gia' il composer abilitato e l'assenza di "Accedi".

         NIENTE flex-wrap: nowrap. Restano ~43 caratteri in mono 10px (~275px)
         che stanno nei 320px utili di un telefono da 360: ma se un giorno non
         ci stessero devono andare A CAPO, non essere tranciati — nowrap dentro
         .chat-shell{overflow:hidden} e' esattamente il meccanismo che ha
         tagliato il testo in CP3. Meglio una riga in piu' che una parola a
         meta'. */
      #chat-who, .chat-meta .sep-who { display: none; }
      .chat-meta { justify-content: center; gap: 8px; padding: 9px 12px; }

      /* La barra documento chiusa costa UNA riga, e la frase di aiuto sparisce:
         "Risponde in chat. Scegli uno stile solo quando vuoi un file da mandare."
         e' utile dove c'e' spazio e qui manderebbe a capo la fascia. Il riepilogo
         dice gia' lo stato; la frase lo SPIEGA, ed e' la spiegazione che si taglia
         prima — come #status-text e .att-titolo piu' sopra.
         L'AVVISO no: quando la frase e' il verdetto di una categoria senza colore
         non e' una spiegazione, e' l'unica cosa che ti dice perche' non e' cambiato
         niente. Va a capo e si prende la sua riga. */
      /* Sotto i 768 la riga degli allegati non deve schiacciare il campo: le
         schede vanno a capo, e il suggerimento sulle tre vie sparisce come
         sparisce .doc-hint — qui il gesto principale e' la fotocamera, non il
         Ctrl+V, e quella frase parlerebbe di cose che sul telefono non esistono. */
      .alle-riga, .alle-barra { padding-left: 13px; padding-right: 13px; }
      .alle-hint { display: none; }
      .alle-card { max-width: 100%; }

      .doc-head { padding: 7px 12px; flex-wrap: wrap; }
      .doc-hint { display: none; }
      .doc-hint.avviso { display: block; flex-basis: 100%; font-size: 11px; }

      /* A 390px il corpo utile e' ~295px: l'etichetta a 74px in colonna fissa
         lascerebbe ~220px alle quattro chip, che andrebbero a capo comunque.
         L'etichetta si prende una riga sua e le chip la larghezza intera. */
      .doc-tray { padding: 10px 12px 12px; }
      .doc-row { display: block; }
      .doc-k { width: auto; display: block; margin-bottom: 6px; }
      .doc-chip { padding: 7px 10px; }
    }

    /* ═══════════════════════════════════════════════════════════════
       COMPATTA — sotto i 600 px
       ═══════════════════════════════════════════════════════════════
       Misurato a 412×915 prima di questo blocco (scripts/misura-console.mjs):
       il registro aveva 587 px, 23 righe di risposta; sotto di lui composer 64
       + allegati 45 + documento 40 + riga di stato 35 = 184 px, piu' header 60
       e barra in basso 58. Il registro era GIA' a flex:1 (regola dei 1100):
       qui non si sblocca spazio, si recupera dal fondo pagina — circa 160 px,
       cioe' sette righe in piu' a riposo, e quasi il doppio con la tastiera
       aperta, dove il fondo pagina pesa in proporzione molto di piu'.

       LAYOUT, NON COMPORTAMENTO. Nessun nodo si sposta e nessun listener
       cambia: la shell diventa una griglia e i contenitori intermedi (il form,
       la zona allegati, la barra documento, la riga di stato) prendono
       `display: contents`, cosi' i loro figli — le stesse foglie di sempre,
       con gli stessi id — sono figli di griglia e si piazzano nella riga del
       composer. Gli inline `style.display` che app.js scrive ('' oppure
       'none') continuano a decidere se una zona esiste: la stringa vuota lascia
       il CSS, 'none' vince su tutto.

       Tutto e' scopato a `:root:not(.vista-piena)`: la classe la mette il
       bottone #vista-toggle per la sessione corrente e basta (niente storage,
       un reload torna compatto), e sopra i 600 px la media query non entra
       comunque — il desktop e' identico per costruzione, e lo si verifica col
       diff del getComputedStyle, non a occhio.

       Colonne della griglia: [6px] allega | foto | documento | campo | invia
       [6px]. Le colonne `auto` vuote (da sloggati allegati e documento sono
       display:none) collassano a zero ma lasciano i gap: ~18 px morti a
       sinistra del campo, solo da sloggati. Accettato.
       Righe: registro 1fr | striscia attivita' | schede allegati | cassetto
       documento | avviso documento | riga composer. */
    .vista-toggle { display: none; }

    @media (max-width: 600px) {
      /* Il toggle c'e' in ENTRAMBI gli stati, altrimenti dalla vista piena non
         si torna: e' l'unica regola qui dentro non scopata alla classe. */
      .vista-toggle {
        display: inline-flex; align-items: center; justify-content: center;
        width: 32px; height: 32px; padding: 0; background: none;
        border: 1px solid var(--border); border-radius: 8px;
        color: var(--text-secondary); cursor: pointer;
      }
      .vista-toggle svg { width: 15px; height: 15px; }
      .vista-toggle[aria-pressed="true"] { border-color: var(--cyan); color: var(--cyan); }

      /* ── header: 44 px, wordmark senza puntini, "esci" resta ── */
      :root:not(.vista-piena) { --header-height: 44px; }
      :root:not(.vista-piena) .header { padding: 0 12px; }
      :root:not(.vista-piena) .header-right { gap: 8px; }
      :root:not(.vista-piena) .header-brand { font-size: .95rem; letter-spacing: .16em; }
      :root:not(.vista-piena) .header-brand span { display: none; }
      /* La pillola di stato e' solo il punto: il testo era gia' nascosto dai
         1100, e la scatola (padding, sfondo, bordo) qui costava ~30 px senza
         dire niente in piu' del colore. #who-bot non si tocca: app.js lo
         mostra solo con piu' di un backend, dove il nome dice QUALE JARVIS
         e' questo — in produzione, dietro il gateway, e' visibile. */
      :root:not(.vista-piena) .status-badge { padding: 0; gap: 0; background: none; border: none; }
      /* Il gruppo destro a larghezze FISSE, perche' #chat-reload sta in un
         altro sottoalbero (la shell della chat) e arriva in header con
         position:fixed: il suo posto dev'essere calcolabile senza leggere
         larghezze. Da destra: [esci | Accedi: 64] [8] [ricarica: 32] [8]
         [toggle: 32]. Il margine del toggle E' lo slot del ricarica.
         Il 08/09 il ricarica stava al centro dell'header, "dove non c'e'
         niente": in produzione c'erano la pillola e #who-bot, e ci finiva
         sopra. Il centro non e' mai vuoto per costruzione; il gruppo destro si'. */
      :root:not(.vista-piena) .header-right .btn-logout,
      :root:not(.vista-piena) .header-right .btn-login {
        box-sizing: border-box; width: 64px; padding-left: 0; padding-right: 0; text-align: center;
      }
      :root:not(.vista-piena) .vista-toggle { margin-right: 40px; }

      /* ── barra in basso: 48 px, stesse sette voci ── */
      :root:not(.vista-piena) .sidebar { height: 48px; }
      :root:not(.vista-piena) .nav-item { width: 48px; height: 34px; }
      :root:not(.vista-piena) .main { padding-bottom: 48px; }
      :root:not(.vista-piena) .panel { padding-bottom: 78px; }
      :root:not(.vista-piena) .panel.panel-chat { padding: 8px 10px; }
      :root:not(.vista-piena) .chat-log { padding: 14px 12px 6px; }

      /* ── la griglia ── */
      :root:not(.vista-piena) .panel-chat .chat-shell {
        display: grid;
        grid-template-columns: 6px auto auto auto minmax(0, 1fr) auto 6px;
        grid-template-rows: minmax(0, 1fr) auto auto auto auto auto;
        column-gap: 6px; row-gap: 0;
        border-radius: 14px;
      }
      :root:not(.vista-piena) .chat-composer,
      :root:not(.vista-piena) .alle-zona,
      :root:not(.vista-piena) .alle-barra,
      :root:not(.vista-piena) .doc-bar,
      :root:not(.vista-piena) .doc-head,
      :root:not(.vista-piena) .chat-meta { display: contents; }

      :root:not(.vista-piena) .chat-shell > .chat-log { grid-row: 1; grid-column: 1 / -1; }
      :root:not(.vista-piena) .chat-shell .chat-activity { grid-row: 2; grid-column: 1 / -1; }
      /* Le schede degli allegati: il bordo solo quando ci sono. Il contatore
         ("1 KB / 15 MB · 0 file validi", ~170 px) sta nella stessa riga di
         griglia, a tutta larghezza e in basso a destra, dentro la fascia
         inferiore del padding delle schede: cosi' non tocca le schede quante
         che siano, e non allarga nessuna colonna — messo nella colonna di
         Invia la allargava di 160 px e restringeva il campo. */
      :root:not(.vista-piena) .alle-riga { grid-row: 3; grid-column: 1 / -1; padding: 10px 12px 28px; }
      :root:not(.vista-piena) .alle-riga:not(:empty) { border-top: 1px solid var(--border); }
      :root:not(.vista-piena) .alle-conta { grid-row: 3; grid-column: 1 / -1; justify-self: end; align-self: end; margin: 0 12px 8px 0; }
      :root:not(.vista-piena) .doc-tray { grid-row: 4; grid-column: 1 / -1; }
      /* L'avviso (categoria senza colore) e' l'unico .doc-hint visibile qui
         sotto — la regola dei 768 nasconde gli altri — e si prende una riga. */
      :root:not(.vista-piena) .doc-hint { grid-row: 5; grid-column: 1 / -1; padding: 6px 12px 0; }

      /* ── la riga del composer ──
         Sfondo e bordo della riga li da' lo pseudo-elemento, piazzato sulla
         stessa riga di griglia sotto alle foglie (z-index 0 contro 1): il form
         e' display:contents e non ha piu' una scatola da colorare. */
      :root:not(.vista-piena) .chat-shell::after {
        content: ''; grid-row: 6; grid-column: 1 / -1; z-index: 0;
        border-top: 1px solid var(--border); background: rgba(5, 10, 20, .6);
      }
      :root:not(.vista-piena) #alle-scegli { grid-column: 2; }
      :root:not(.vista-piena) #alle-foto { grid-column: 3; }
      :root:not(.vista-piena) #doc-sum { grid-column: 4; }
      :root:not(.vista-piena) #chat-input { grid-column: 5; }
      :root:not(.vista-piena) #chat-send,
      :root:not(.vista-piena) #chat-login-btn { grid-column: 6; }
      :root:not(.vista-piena) #alle-scegli,
      :root:not(.vista-piena) #alle-foto,
      :root:not(.vista-piena) #doc-sum,
      :root:not(.vista-piena) #chat-input,
      :root:not(.vista-piena) #chat-send,
      :root:not(.vista-piena) #chat-login-btn { grid-row: 6; z-index: 1; align-self: end; margin: 8px 0; }

      /* Le tre icone: stessi bottoni, testo a zero, svg piu' grande. */
      :root:not(.vista-piena) #alle-scegli,
      :root:not(.vista-piena) #alle-foto,
      :root:not(.vista-piena) #doc-sum {
        width: 36px; height: 36px; padding: 0; gap: 0; justify-content: center;
        font-size: 0; letter-spacing: 0; border-radius: 9px;
      }
      :root:not(.vista-piena) #alle-scegli .alle-clip,
      :root:not(.vista-piena) #alle-foto .alle-clip { width: 18px; height: 18px; }
      /* L'icona Documento e' lo swatch che docPaint colora gia' (grigio senza
         scelta, il colore della categoria con formato+categoria), ritagliato a
         foglio con l'angolo piegato. Il bordo ciano di .scelto resta. */
      :root:not(.vista-piena) #doc-sum-txt { display: none; }
      :root:not(.vista-piena) #doc-sum .doc-sw {
        width: 15px; height: 19px; border-radius: 2px; box-shadow: none;
        clip-path: polygon(0 0, 62% 0, 100% 34%, 100% 100%, 0 100%);
      }
      :root:not(.vista-piena) #chat-input { padding: 8px 4px; }

      /* Invia = freccia, Stop = quadrato rosso, stessa scatola 40×40. Il testo
         ("Invia"/"Stop") lo scrive ancora app.js: qui e' solo a font-size 0. */
      :root:not(.vista-piena) #chat-send {
        width: 40px; height: 40px; padding: 0; font-size: 0; border-radius: 12px;
        display: flex; align-items: center; justify-content: center;
      }
      :root:not(.vista-piena) #chat-send::before {
        content: ''; width: 18px; height: 18px; background: currentColor;
        -webkit-mask: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 4l7 7-1.4 1.4L13 7.8V20h-2V7.8l-4.6 4.6L5 11z'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 4l7 7-1.4 1.4L13 7.8V20h-2V7.8l-4.6 4.6L5 11z'/%3E%3C/svg%3E") center / contain no-repeat;
      }
      :root:not(.vista-piena) #chat-send.stop::before {
        width: 14px; height: 14px; border-radius: 2px; -webkit-mask: none; mask: none;
      }

      /* ── la riga di stato sparisce; "ricarica" resta, in header ──
         Stesso nodo #chat-reload, stesso listener: solo position:fixed nello
         slot del gruppo destro, fra il toggle e "esci" (vedi sopra: 12 di
         padding + 64 del bottone + 8 di gap = 84 da destra). */
      :root:not(.vista-piena) .chat-meta > span { display: none; }
      :root:not(.vista-piena) #chat-reload {
        position: fixed; top: 6px; right: 84px; z-index: 60;
        width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
        font-size: 0; text-decoration: none;
        border: 1px solid var(--border); border-radius: 8px;
        background: rgba(6, 11, 24, .6); color: var(--text-secondary);
      }
      :root:not(.vista-piena) #chat-reload::before { content: '\21bb'; font-size: 17px; line-height: 1; }
    }

    /* ═══════════════════════════════════════════════════════════════
       STAMPA ED ESPORTAZIONE IN PDF
       ═══════════════════════════════════════════════════════════════
       La console e' a tema scuro. In stampa il browser scarta gli SFONDI ma
       tiene i COLORI DEL TESTO: risultato, bianco su bianco. Un PDF che sembra
       vuoto e che invece il testo ce l'ha, solo invisibile.

       Il difetto piu' grave pero' non e' il colore: e' che OGNI contenitore
       della catena taglia. #app ha un'altezza fissa, .main e .content hanno
       overflow:hidden, .panel e .chat-log scrollano. In stampa quello ritaglia
       il documento a una schermata sola, e il resto della conversazione non
       finisce nel file — un guasto silenzioso, perche' il PDF si apre e sembra
       completo. Qui la catena si apre tutta.

       Cosa resta: la conversazione. Cosa sparisce: il cromo e i comandi, che
       su carta non si premono. Il pannello che si stampa e' quello APERTO,
       deciso da .active — non un elenco di sezioni da tenere allineato. */
    @media print {
      /* Quasi tutti i colori passano dalle variabili: ridefinirle qui ribalta
         in un colpo ogni regola che le usa, invece di riscriverne cinquanta e
         doverle poi tenere allineate a quelle di sopra. */
      :root {
        --bg-deep: #fff; --bg-panel: #fff; --bg-card: #fff;
        --bg-card-hover: #fff; --bg-sidebar: #fff;
        --text-primary: #000;
        --text-secondary: #444;
        --text-tertiary: #666;
        --border: #ccc; --border-hover: #999;
        --cyan: #005b73; --cyan-dim: #ddd; --cyan-glow: transparent;
        --cyan-bright: #005b73;
        --gold: #6b4e00; --gold-dim: #ddd;
        --green: #0a5c2a; --green-dim: #ddd;
        --red: #a01010;
      }

      @page { margin: 14mm; }
      html, body { background: #fff; color: #000; }

      /* Via quello che non e' la conversazione: navigazione, intestazione,
         comandi e decorazione. Un bottone stampato non si preme, e la riga
         "cronologia condivisa con Telegram · ricarica" su carta non porta da
         nessuna parte — la stessa regola dei bottoni che non si mostrano. */
      .grid-pattern, #boot-screen, .sidebar, .header, .footer,
      .chat-composer, .chat-activity, .chat-meta, .chat-suggests,
      .doc-bar,
      .msg-azioni, .section-header .line { display: none !important; }

      /* LA CATENA CHE TAGLIAVA. Senza queste righe il PDF contiene una
         schermata e basta. */
      #app, .main, .content, .panel, .chat-shell, .chat-log {
        height: auto !important;
        max-height: none !important;
        min-height: 0 !important;
        overflow: visible !important;
      }
      #app, .main, .content, .chat-shell, .chat-log { display: block !important; }
      /* Solo il pannello aperto: gli altri restano al loro display:none. */
      .panel.active { display: block !important; }
      .panel { padding: 0 !important; }

      /* Le superfici scure diventano carta. */
      .chat-shell {
        background: none !important; border: none !important;
        box-shadow: none !important; border-radius: 0 !important;
      }
      .chat-shell::before { display: none !important; }
      .msg.user .msg-text { background: none !important; }
      .msg-avatar { background: none !important; }
      /* Il grassetto dei messaggi e' un #fff LETTERALE (.msg-text strong), non
         passa dalle variabili: senza questa riga restava invisibile su carta
         anche dopo aver ribaltato tutto il resto. E' l'unico colore di testo
         chiaro scritto a mano in tutto il foglio — verificato con un grep sui
         letterali, non a memoria. */
      .msg-text strong { color: #000 !important; }

      /* Il riepilogo si stampa aperto. "dettagli ▾" e' un invito a toccare, e
         su carta non si tocca: sotto i 768 la regola del collasso vale anche
         in stampa, perche' quel media query non dichiara un tipo. */
      .msg-det { display: none !important; }
      .msg-foot > * { display: inline-flex !important; }

      /* Un messaggio non si spezza fra due pagine se puo' evitarlo. */
      .msg { break-inside: avoid; page-break-inside: avoid; }
    }

          #section-marketing .mkt-card{background:var(--bg-card);border:1px solid var(--border);border-radius:14px;padding:20px;margin-bottom:16px}
          #section-marketing .mkt-muted{color:var(--text-secondary,#8a94a6);font-size:14px}
          .mkt-userbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
          .mkt-userbar #mkt-user{font-family:var(--font-mono);color:var(--cyan);font-size:13px}
          .mkt-form{background:var(--bg-card);border:1px solid var(--border);border-radius:14px;padding:20px;margin-bottom:18px}
          .mkt-row{display:flex;gap:14px;flex-wrap:wrap;margin-bottom:14px}
          .mkt-row label{display:flex;flex-direction:column;gap:6px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--text-secondary,#8a94a6);flex:1;min-width:150px}
          .mkt-row label.grow{flex:1 1 100%}
          .mkt-row input,.mkt-row select{background:var(--bg-deep,#0b0f17);border:1px solid var(--border);border-radius:8px;padding:10px 12px;color:var(--text-primary);font-family:var(--font-sans);font-size:14px}
          .mkt-row input:focus,.mkt-row select:focus{outline:none;border-color:var(--cyan)}
          .mkt-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
          .mkt-btn{border:1px solid var(--border);background:transparent;color:var(--text-primary);padding:10px 18px;border-radius:8px;font-family:var(--font-sans);font-size:14px;cursor:pointer;transition:all .15s}
          .mkt-btn.primary{background:var(--cyan);border-color:var(--cyan);color:#04121a;font-weight:600}
          .mkt-btn.primary:hover{filter:brightness(1.12)}
          .mkt-btn.ghost:hover{border-color:var(--cyan);color:var(--cyan)}
          .mkt-btn:disabled{opacity:.5;cursor:not-allowed}
          .brief{background:var(--bg-card);border:1px solid var(--border);border-left:3px solid var(--cyan);border-radius:12px;padding:18px;margin-bottom:14px}
          .brief h3{font-size:15px;margin:0 0 4px;color:var(--text-primary)}
          .brief .meta{font-family:var(--font-mono);font-size:12px;color:var(--gold);margin-bottom:12px}
          .brief .field{margin-bottom:8px;font-size:14px;line-height:1.55;color:var(--text-primary)}
          .brief .field b{color:var(--cyan);font-weight:600}
          .brief ul{margin:4px 0 8px 18px;padding:0}
          .brief li{font-size:13px;line-height:1.5;margin-bottom:3px;color:var(--text-primary)}
          .brief .fb{display:flex;gap:8px;margin-top:12px}
          .brief .fb button{border:1px solid var(--border);background:transparent;border-radius:8px;padding:6px 14px;cursor:pointer;font-size:14px;color:var(--text-primary)}
          .brief .fb button.on{border-color:var(--cyan);color:var(--cyan);background:rgba(56,189,248,.08)}
          .brief.warn{border-left-color:var(--gold);color:var(--gold);font-size:13px}
          .mkt-hist-item{border-bottom:1px solid var(--border);padding:9px 0;font-size:13px;display:flex;justify-content:space-between;gap:12px;color:var(--text-primary)}
          .mkt-hist-item .st{font-family:var(--font-mono);font-size:11px;color:var(--text-secondary,#8a94a6);white-space:nowrap}
