
  /* Toolbar — canvas spec §4: one row, exactly 52px, never wraps. The title block is the
     only thing that gives way (name ellipses down to 120px). */
  #toolbar{
    display:flex; align-items:center; gap:8px; padding:8px 14px; height:52px; flex:none; flex-wrap:nowrap;
    background:var(--surface-default); border-bottom:1px solid var(--border); z-index:20; position:relative;
  }
  #toolbar > *{flex:none;}
  #toolbar > .spacer{flex:1; min-width:0;}
  #toolbar button{white-space:nowrap;}
  /* ---- Title block (Drawing Set §4, the signature move) ----
     SURVEY · PAGES · STATUS labels over the name, the page count and the stamp; 44px tall (§4 amendment)
     inside the 52px toolbar (2+13+1+19 = 35 of content). The name cell is a one-track grid
     — minmax(auto, max-content) — so it shrinks (the name ellipses) but never below its
     label row's minimum — and in that row only #saveState is incompressible (the kind word
     and the presence line sit in minmax(0, max-content) columns: they widen the cell when
     there is room and ellipse when there is not), which is why #saveState never clips. */
  .tblock{flex:0 1 auto; min-width:220px; height:44px; display:flex; border:1px solid var(--border-control);
    border-radius:var(--r-control); background:var(--surface-default); overflow:hidden;}
  #toolbar .tblock{flex:0 1 auto; margin-right:4px;}
  #toolbar .tblock.nested{min-width:120px;} /* a nested editor's block is the name cell alone (PAGES/STATUS hidden): the canvas spec's 120px title minimum, so Back still fits at 1280 */ /* beats "#toolbar > *{flex:none}" — the title block is the one toolbar item that gives way */
  .tb-cell{display:flex; flex-direction:column; justify-content:center; gap:3px; padding:0 14px; flex:none; min-width:0;}
  .tb-cell + .tb-cell{border-left:1px solid var(--border-control);}
  .tb-cell[hidden]{display:none;}
  .tb-name{flex:0 1 auto; max-width:360px; display:grid; grid-template-columns:minmax(auto, max-content); align-content:center; row-gap:3px;}
  .tb-lbl{height:13px; font-size:11px; line-height:13px; font-weight:600; font-stretch:var(--stretch-label); letter-spacing:.08em;
    text-transform:uppercase; color:var(--text-muted); white-space:nowrap;}
  .tb-name{min-width:auto;} /* the label row's minimum is a floor (see above) — .tb-cell's min-width:0 must not undercut it */
  .tb-name .tb-lbl{display:grid; grid-auto-flow:column; grid-template-columns:minmax(0, max-content) max-content; grid-auto-columns:minmax(0, max-content); column-gap:0; align-items:center;}
  .tb-name .tb-lbl > #tbKind{padding-right:0;}
  #tbKind::after{content:""; display:inline-block; width:8px;} /* the gap sits inside the clipped box, so a collapsed kind word takes its gap with it (padding would leave an 8px stub) */
  /* What gives way when the toolbar is tight (hosted 1280: offline save string + issue chip + Comments):
     1. the Comments label → its count (below 1366px), 2. the SURVEY kind word, 3. the name ellipses to
     its floor. #saveState, PAGES and STATUS never clip. A new toolbar item must join this order —
     it may not eat into the stamp. (Guardian ruling 2026-10-06, drawing-set-identity.md §4.) */
  .cmt-short{display:none;}
  @media (max-width:1365px){
    #toolbar .cmt-long{display:none;}
    #toolbar .cmt-short{display:inline; font-variant-numeric:tabular-nums;}
    #toolbar #commentsIndexBtn{padding:0 10px; gap:6px;}
  }
  .tb-name .tb-lbl > .tb-presence{padding-left:8px;}
  #tbKind{min-width:0; overflow:hidden; text-overflow:ellipsis;} /* under real pressure the kind word gives way, never the save state */
  #toolbar #saveState, .tb-presence{font-stretch:100%; letter-spacing:0; text-transform:none; font-weight:400; font-size:11.5px; color:var(--text-muted);}
  #toolbar #saveState{display:inline-flex; align-items:center; gap:4px; width:auto; min-width:0; height:13px; line-height:13px; font-size:11.5px; overflow:visible;}
  #toolbar #saveState .nf-i{width:12px; height:12px;}
  /* Accounts review fix 3: each item keeps its own column. With the kind word hidden the save state
     used to fall into the shrinkable first column and spill over the presence line. */
  #toolbar .tb-name .tb-lbl > #tbKind{grid-column:1;}
  #toolbar .tb-name .tb-lbl > #saveState{grid-column:2;}
  #toolbar .tb-name .tb-lbl > .tb-presence{grid-column:3;}
  /* renderSaveStateEl() rewrites className (st-saved/st-failed/…), so these key off the id. */
  .tb-presence{min-width:0; overflow:hidden; text-overflow:ellipsis;}
  .tb-presence .nf-avatar{display:none;} /* an 18px avatar can't sit in a 13px label row; the full sentence is in title */
  .tb-val{display:block; min-width:0; font-size:15px; line-height:19px; font-weight:600; letter-spacing:-0.005em; color:var(--text-primary);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  .tb-mono{font-family:var(--font-mono); font-size:14px; line-height:19px; font-weight:500; letter-spacing:0; color:var(--text-primary);}
  /* The issue stamp (overrides the global button rule): DRAFT outlined in ink, ISSUED filled blue. */
  .stamp, #toolbar .stamp{height:20px; padding:0 8px; border-radius:var(--r-stamp); border:1px solid var(--text-primary); background:transparent;
    color:var(--text-primary); font-size:11px; line-height:18px; font-weight:600; font-stretch:var(--stretch-label); letter-spacing:.10em;
    text-transform:uppercase; white-space:nowrap; display:inline-flex; align-items:center; align-self:flex-start; gap:0;
    transition:background-color var(--dur-2) var(--ease-step), border-color var(--dur-2) var(--ease-step), color var(--dur-2) var(--ease-step);}
  button.stamp:hover, #toolbar button.stamp:hover{background:var(--surface-sunken); border-color:var(--text-primary); color:var(--text-primary);}
  .stamp.issued, #toolbar .stamp.issued{background:var(--brand-600); border-color:var(--brand-600); color:var(--text-on-accent);}
  button.stamp.issued:hover, #toolbar button.stamp.issued:hover{background:var(--brand-700); border-color:var(--brand-700); color:var(--text-on-accent);}
  /* On hold (spec plans §5): sharing is on but the workspace's month of answers is used. Not filled:
     the filled stamp means answers can arrive. */
  .stamp.hold, #toolbar .stamp.hold{background:transparent; border-color:var(--warning-fg); color:var(--warning-fg);}
  button.stamp.hold:hover, #toolbar button.stamp.hold:hover{background:var(--warning-bg); border-color:var(--warning-fg); color:var(--warning-fg);}
  .stamp:focus-visible{outline:2px solid var(--brand-600); outline-offset:2px;}
  span.stamp{cursor:default;}
  #toolbar .tb-icon{width:34px; height:34px; padding:0;}
  #toolbar .tb-caret{display:inline-flex; margin-left:-2px; color:var(--text-muted);}
  #simBadge{display:inline-block; max-width:220px; min-width:0; flex:0 1 auto !important; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
  #simBadge:empty{display:none;}

  /* Status chip (replaces #validateMsg) — hidden until the first validation. */
  #toolbar .status-chip{height:26px; padding:0 10px; border-radius:var(--r-chip); border:none; font-size:12px; font-weight:600; gap:5px;}
  #toolbar .status-chip.err, #toolbar .status-chip.err:hover{background:var(--error-bg); color:var(--error-fg);}
  #toolbar .status-chip.warn, #toolbar .status-chip.warn:hover{background:var(--warning-bg); color:var(--warning-fg);}
  #toolbar .status-chip.ok{background:transparent; color:var(--success-fg); align-items:center; flex:none;}
  #toolbar .status-chip:not(.ok):hover{box-shadow:inset 0 0 0 1px currentColor;}
  .cmt-pop.issues-pop{width:360px; max-height:320px; display:flex; flex-direction:column;}
  .issues-pop .issues-body{overflow-y:auto; flex:1;}
  .issues-pop .issue-row{font-size:12.5px; line-height:1.45; color:var(--text-primary); padding:10px 14px; border-top:1px solid var(--border-default);}
  .issues-pop .issue-row:first-child{border-top:0;}

  /* Test ▾ / More menus — A2 §1 popover; Drawing Set §5: radius 6, --border-strong edge,
     --shadow-2, items radius 4 with --brand-50 hover. */
  .tb-menu-wrap{position:relative; display:flex; align-items:center;}
  .tb-menu{position:absolute; right:0; top:calc(100% + 6px); min-width:240px; background:var(--surface-default);
    border:1px solid var(--border-strong); border-radius:var(--r-card); box-shadow:var(--shadow-2); padding:6px; z-index:60;
    display:flex; flex-direction:column;}
  .tb-menu[hidden]{display:none;}
  .tb-menu .tb-menu-item{justify-content:flex-start; width:100%; font-size:13px; padding:8px 10px; border-radius:var(--r-control); border:none;
    background:transparent; color:var(--text-primary); gap:8px; text-align:left;}
  .tb-menu .tb-menu-item:hover, .tb-menu .tb-menu-item:focus-visible{background:var(--brand-50); border:none;}
  .tb-menu .tb-menu-item:focus-visible{outline:2px solid var(--brand-600); outline-offset:-2px;}
  .tb-menu .tb-menu-item.danger-item{color:var(--error-fg);}
  .tb-menu .tb-menu-sep{height:1px; background:var(--border-default); margin:6px 4px;}
  /* Popover entrance (spec §6) — opacity + 2px, 120ms, step easing. Nothing bounces. */
  @keyframes nf-pop-in{from{opacity:0; transform:translateY(-2px);}to{opacity:1; transform:none;}}
  .tb-menu:not([hidden]), .cmt-pop, .export-menu, .identity-menu.show, #vizTip{animation:nf-pop-in var(--dur-2) var(--ease-step);}

  /* Buttons (spec §5) — radius 4, 1px ink hairline, 13/500. Toolbar buttons stay 34px
     (7 + 18 + 7 + 2 border). Only colour, background and border animate, at 90ms. */
  button, .tpl-import-label{
    font:inherit; cursor:pointer; border:1px solid var(--border-control); background:var(--surface-default);
    color:var(--text-primary); padding:7px 15px; border-radius:var(--r-control); font-size:13px; font-weight:500; line-height:18px;
    transition:background-color var(--dur-1) var(--ease-step), border-color var(--dur-1) var(--ease-step), color var(--dur-1) var(--ease-step);
    display:inline-flex; align-items:center; justify-content:center; gap:7px;
  }
  .nf-i{flex:none; display:inline-block; vertical-align:-2px;}
  button:hover{border-color:var(--text-secondary); background:var(--surface-sunken); color:var(--text-primary);}
  button.primary{background:var(--brand-600); border-color:var(--brand-600); color:var(--text-on-accent); font-weight:600;}
  button.primary:hover{background:var(--brand-700); border-color:var(--brand-700); color:var(--text-on-accent);}
  button.primary:active{background:var(--brand-800); border-color:var(--brand-800);}
  button.good{background:var(--surface-default); border-color:var(--border-control); color:var(--text-primary); font-weight:600;}
  button.good:hover{border-color:var(--text-secondary); background:var(--surface-sunken);}
  button.ghost, .tpl-import-label{background:transparent;}
  button.ghost:hover, .tpl-import-label:hover{background:var(--brand-50); border-color:var(--border-control);}
  button.danger{color:var(--error-fg); border-color:var(--border-control);}
  button.danger:hover{border-color:var(--error-fg); background:var(--error-bg); color:var(--error-fg);}
  button:disabled, button:disabled:hover{background:var(--surface-subtle); color:var(--text-faint); border-color:var(--border-default); cursor:not-allowed;}
  button:focus-visible{outline:2px solid var(--brand-600); outline-offset:2px;}

  /* Inputs, selects, textareas (spec §5) — zero-specificity defaults; every component rule
     still wins. h32, radius 4, ink hairline, white, ink 13px; placeholder never faint. */
  :where(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden],.inline-edit,.resp-input), select:not(.tiny-select,.resp-input)){height:32px;}
  :where(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]), select, textarea){
    font:inherit; font-size:13px; color:var(--text-primary); background:var(--surface-default);
    border:1px solid var(--border-control); border-radius:var(--r-control); padding:0 10px;
    transition:border-color var(--dur-1) var(--ease-step);}
  :where(textarea){padding:8px 10px;}
  :where(input, textarea)::placeholder{color:var(--text-muted); opacity:1;}
  :where(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file]), select, textarea):where(:hover){border-color:var(--text-secondary);}
  :where(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file]), select, textarea):where(:focus){border-color:var(--brand-600); outline:2px solid var(--brand-600); outline-offset:1px;}
  :where(input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"]){border-color:var(--error-fg);}
  .nf-field-err{display:flex; align-items:center; gap:6px; font-size:12px; color:var(--error-fg); margin-top:4px;}
  .spacer{flex:1;}

  /* Main layout */
  #main{flex:1; display:flex; min-height:0;}

  /* ============================== NARROW TOOLBAR — spec docs/specs/narrow-layouts.md §3 ==============================
     52px, one row, never wraps. Give-way below 1024: Comments → count (already ruled), the
     labelled ghost buttons go icon-only (names kept in aria-label/title), Preview shortens,
     the kind word collapses, the name ellipses to a 96px floor. Save state, PAGES and STATUS
     never clip. ≤767: menu · title block · More · Preview; the rest lives in More. */
  #toolbar .tb-short, .nl-only, .nl-note, #toolbar .ss-short{display:none;}
  /* The give-way follows the toolbar's OWN width (a container query), not the viewport's: at
     1024 the full 248px sidebar leaves the toolbar only 776px, which is narrower than the
     rail band's toolbar at 1023. */
  #toolbar{container:toolbar / inline-size;}
  @container toolbar (max-width:1039px){
    #toolbar .tb-iconable{width:34px; height:34px; padding:0; justify-content:center; gap:0;}
    #toolbar .tb-iconable.tb-caretted{width:auto; padding:0 6px 0 9px; gap:2px;}
    #toolbar .tb-iconable .tb-txt{display:none;}
    #toolbar .tb-preview .tb-long{display:none;}
    #toolbar .tb-preview .tb-short{display:inline;}
    #toolbar .tb-name{min-width:96px;}
    #toolbar #tbKind{display:none;} /* step 4: the kind word collapses whole — a cut "SURVE…" reads broken */
  }
  /* Narrow toolbar: the save state shows its short form (full sentence kept in title and the
     accessible name; the save-failure bar still escalates). Cells tighten on a phone. */
  @container toolbar (max-width:719px){
    #toolbar #saveState .ss-long{display:none;}
    #toolbar #saveState .ss-short{display:inline;}
  }
  @container toolbar (max-width:479px){
    #toolbar .tb-cell{padding:0 10px;}
  }
  @media (max-width:767px){
    #toolbar{gap:8px; padding:8px 12px;}
    #toolbar .tb-wide-only, #toolbar #commentsIndexBtn{display:none;}
    #toolbar .tb-menu .nl-only{display:flex;}
    #toolbar .tb-menu .tb-menu-sep.nl-only{display:block;}
    #toolbar .tb-menu #nlCommentsItem[style*="none"]{display:none;}
    #toolbar .tb-preview{width:34px; height:34px; padding:0; justify-content:center; gap:0;}
    #toolbar .tb-preview .tb-short{display:none;}
    #toolbar .tblock{flex:1 1 auto; min-width:0;}
    /* the issues chip floats at the canvas foot, opposite the zoom cluster — it keeps its icon,
       count and word, and opens its list upward */
    #toolbar #statusChip, #toolbar #statusOk{position:fixed; right:16px; bottom:64px; /* above the zoom cluster (bottom 20 + 32 + 12) */ z-index:12; height:32px;
      background:var(--surface-default); border:1px solid var(--border-control);}
    #toolbar #statusChip.err{background:var(--error-bg); border-color:var(--error-fg);}
    #toolbar #statusChip.warn{background:var(--warning-bg); border-color:var(--warning-fg);}
    .nl-note{display:flex; align-items:center; gap:10px; padding:10px 14px; background:var(--surface-subtle); border-bottom:1px solid var(--border-default);
      font-size:13px; line-height:18px; color:var(--text-secondary); flex:none; flex-wrap:wrap;}
    .nl-note > .nf-i{color:var(--text-secondary); flex:none;}
    .nl-note-text{flex:1 1 220px; min-width:0;}
    .nl-note-actions{display:flex; align-items:center; gap:8px; margin-left:auto;}
    .nl-note-actions button{height:34px; padding:0 12px; white-space:nowrap;}
    .nl-note-actions .nl-note-x{width:34px; padding:0; justify-content:center;}
    body.nl-note-dismissed .nl-note{display:none;}
  }
