/* TensorVortex design language: values pulled directly from
   tensorvortex.com's live computed styles (getComputedStyle against
   :root and real rendered buttons/headings), not approximated from a
   screenshot. Variable names kept as this file's own (--paper, --ink,
   etc.) rather than renamed to TensorVortex's own (--color-canvas,
   --color-ink, etc.): a value swap gets the same visual result as a
   full rename, without touching every one of this file's existing
   usages. See doc/agent-council-architecture.md.

   Re-measured 2026-09-20, direct user request ("study TensorVortex's
   look and feel... I want it to be exactly the same"), against real
   rendered elements on tensorvortex.com (not just its :root custom
   properties, which is as far as the first pass above went): --line
   and --line-strong were both approximated, not exact, and --muted's
   single value was being asked to do two jobs TensorVortex actually
   keeps separate -- its real eyebrow/label color (which --muted
   already matched) and a distinctly darker color real body copy and
   descriptive notes use (introduced below as --ink-secondary, not a
   --muted overwrite, since every existing --muted usage that really is
   a small eyebrow-style label was already correct and would have gone
   wrong the other way). */
:root {
  --paper: #faf9f5;        /* TV --color-canvas */
  --paper-deep: #efe9de;   /* TV --color-surface-card */
  --surface: #fdfcf8;      /* TV --color-canvas-soft */
  --ink: #141413;          /* TV --color-ink */
  --ink-secondary: #3d3d3a; /* TV's real body-copy/muted-note color (measured on a live <p>), distinct from --muted's own label/eyebrow color below */
  --muted: #6c6a64;        /* TV --color-muted -- correct as measured on TV's own eyebrow text, not a mismatch */
  --line: #e6dfd8;         /* corrected 2026-09-20: measured live on TV's own nav/card border, was #ebe6df */
  --line-strong: #d6d3d1;  /* corrected 2026-09-20: measured live on TV's own outline-button border, was #d8d2c6 */
  --terracotta: #c25e3a;   /* TV --color-primary */
  --terracotta-dark: #9c4a2c; /* darkened --terracotta; TV exposes no primary-active token */
  --terracotta-darker: #7c3a22; /* .primary-button's hover shade -- see that rule's own comment */
  --sage: #5d8a6b;         /* TV --color-secondary */
  --sage-dark: #4a6d55;    /* darkened --sage, same ~20% ratio as --terracotta-dark; see .journey-step.done's own comment */
  /* 2026-09-20: no danger/error color existed anywhere in this file before
     Delete Project/Artifact needed one (destructive-emphasis: destructive
     actions need a semantic danger color, visually separated from primary
     actions). A warm brick red, not a pure alarm red, to sit next to
     --terracotta without looking like a foreign design system. */
  --danger: #b3413a;
  --danger-dark: #8f3129;
  /* 2026-09-20, Lean Canvas boxes: "needs revision" is not an error and
     not a success, and this palette had no third state -- --danger would
     read as "something is broken" for what is really "worth another
     look." A warm ochre, mixed from the same earth family as
     --terracotta, so the canvas still looks like this product. The dark
     variant is the text one: --amber itself measures ~3.3:1 on --paper,
     below AA for the 10px flag it labels, while --amber-dark measures
     ~5.1:1. Same border-vs-text split --danger already uses. */
  --amber: #b8862e;
  --amber-dark: #8a6318;
  --cream: #fdfcf8;        /* TV --color-canvas-soft */
  --radius: 8px;           /* TV's real button/card corner radius (measured live), was 0 (hard square) */
  --shadow: 0 22px 70px rgba(71, 52, 37, 0.09);
  --serif: "EB Garamond", "Source Serif Pro", "Times New Roman", serif;
  --sans: "Inter", "Avenir Next", "Helvetica Neue", Helvetica, sans-serif;
  --mono: "Geist Mono", "JetBrains Mono", "SFMono-Regular", Consolas, monospace;
}

* { box-sizing: border-box; }
/* TensorVortex's own bordered/card surfaces measure 8px (--radius) live,
   not the hard square corners this file used before. One shared rule
   here instead of editing every surface selector individually; true
   circles (.journey-step-circle, .live-dot) set border-radius: 50% in
   their own, more specific rule further down and are unaffected.
   .brand-mark is deliberately excluded, it is this app's own logo
   mark, not a generic card, and has no TensorVortex equivalent to
   match. */
.path-card, .input-panel, .desk-aside, .emerging-panel, .room-brief, .workshop-input,
textarea, .voice-recorder-button, .voice-recorder-icon, .upload-icon,
.transcript, .reply-box, .polish-draft-output, .reason-box,
.format-option, .room-feedback, .manuscript-row, .login-card, .login-form input,
.institute-card, .toast, .book-goal-toggle, .evidence-form input, .evidence-form select {
  border-radius: var(--radius);
}
/* The hidden attribute is the app's one visibility toggle (showScreen,
   the journey stepper, topbar-meta). Any element given an explicit
   display in its own rule would otherwise ignore it, .topbar-meta did. */
[hidden] { display: none !important; }
html { scroll-behavior: smooth; }
body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans); }
button, textarea { font: inherit; }
button { cursor: pointer; }
button:focus-visible, textarea:focus-visible, a:focus-visible { outline: 3px solid rgba(185, 86, 62, 0.34); outline-offset: 3px; }
/* showScreen() gives each screen's heading tabindex="-1" and focuses it
   on every navigation, for screen-reader users -- that focus call is the
   *only* way any h1/h2/h3 in this app ever receives focus, since
   tabindex="-1" removes it from the normal Tab order a sighted keyboard
   user would otherwise cycle through. Direct user feedback, screenshots
   from multiple different screens including login: a visible ring
   (previously reskinned here from the browser's default blue to the
   site's own terracotta, rather than removed) was showing on literally
   every screen transition for every visitor, not just keyboard users --
   because it can never be a real "user tabbed here" case, there's no
   scenario where a visible indicator is actually earning its keep.
   Screen readers announce the focus change from the DOM state itself,
   independent of whether anything is drawn on screen, so removing the
   ring outright costs real keyboard/screen-reader users nothing. */
h1:focus-visible, h2:focus-visible, h3:focus-visible { outline: none; }

.app-shell { min-height: 100vh; background: radial-gradient(circle at 50% -20%, #fffdf8 0, var(--paper) 54%); }
.topbar { height: 76px; display: flex; align-items: center; justify-content: space-between; padding: 0 clamp(22px, 5vw, 76px); border-bottom: 1px solid rgba(198, 187, 171, 0.62); }
.brand { display: inline-flex; align-items: center; gap: 10px; color: var(--ink); font: 600 18px var(--serif); letter-spacing: 0.02em; text-decoration: none; }
.brand-mark { display: grid; place-items: center; width: 30px; height: 30px; border: 1px solid var(--terracotta); color: var(--terracotta); font: 600 14px var(--mono); }
.topbar-meta { display: flex; align-items: center; gap: 22px; color: var(--muted); font-size: 12px; }
.quiet-button, .back-button, .text-button { border: 0; background: transparent; color: var(--muted); padding: 7px 0; font-size: 12px; }
/* Book and session history, one level in from the topbar now (audit §3) --
   quiet text links under the Projects screen's own intro copy, not
   buttons competing with the primary "Back to home" action. */
/* .workspace-head p (elsewhere in this file) sets margin:0 on every
   paragraph in this header at higher specificity (class+tag) than a
   plain .projects-secondary-links class rule could win against -- same
   conflict already found live on #project-home-status-line, applied
   here pre-emptively instead of rediscovering it the same way twice. */
.workspace-head .projects-secondary-links { display: flex; gap: 18px; margin: 10px 0 0; }
.projects-secondary-links .text-button { padding: 0; text-decoration: underline; text-underline-offset: 3px; }
.projects-secondary-links .text-button:hover { color: var(--terracotta-dark); }
.quiet-button:hover, .back-button:hover, .text-button:hover { color: var(--terracotta-dark); }

/* Journey A only (bring a thought -> destination chosen), per
   app.js's renderJourneyStepper. Journey B, the book's own longer
   production journey, deliberately has no stepper here: it lives on its
   own separate screens instead. */
.journey-stepper { padding: 16px clamp(22px, 5vw, 76px); border-bottom: 1px solid rgba(198, 187, 171, 0.62); background: var(--paper-deep); }
.journey-stepper ol { display: flex; align-items: center; gap: 0; list-style: none; margin: 0; padding: 0; max-width: 760px; }
.journey-step { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.journey-step:not(:last-child) { flex: 1 1 auto; }
.journey-step:not(:last-child)::after { content: ""; flex: 1 1 auto; height: 1px; margin: 0 14px; background: var(--line); }
.journey-step-circle { flex: 0 0 auto; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; border: 1.5px solid var(--muted); color: var(--muted); font: 600 11px var(--mono); background: var(--paper-deep); }
.journey-step-label { flex: 0 0 auto; color: var(--muted); font-size: 13px; white-space: nowrap; }
/* Same audit finding as .primary-button above, same fix: white text at
   11px on the plain accent colors measured 3.95:1 (sage) / 4.24:1
   (terracotta), both below the 4.5:1 AA floor. The -dark shades pass. */
.journey-step.done .journey-step-circle { border-color: var(--sage-dark); background: var(--sage-dark); color: #fff; }
.journey-step.done .journey-step-label { color: var(--ink); }
.journey-step.current .journey-step-circle { border-color: var(--terracotta-dark); background: var(--terracotta-dark); color: #fff; }
.journey-step.current .journey-step-label { color: var(--ink); font-weight: 600; }

.screen { width: min(1180px, calc(100% - 44px)); margin: 0 auto; padding: clamp(58px, 8vw, 104px) 0 72px; }
.screen[hidden] { display: none; }
/* Corrected 2026-09-20: TV's own eyebrow text (measured live, e.g. "For
   mentors and coaches" on its homepage) is Inter at 11px/600 with 2px
   absolute letter-spacing, not the monospace guess this rule used
   before -- checked directly rather than assumed, since a serif/sans/
   mono three-font system makes "which one is this label" a real
   question, not an obvious default. */
.eyebrow, .path-kicker, .aside-label, .map-label, .room-status, .reason-label { color: var(--terracotta); font: 600 11px var(--sans); letter-spacing: 2px; text-transform: uppercase; }
.hero-grid { display: grid; grid-template-columns: minmax(0, 1fr) 230px; gap: clamp(40px, 8vw, 128px); align-items: end; margin-top: 20px; }
h1, h2, h3, p { margin-top: 0; }
/* Screen-by-screen consistency pass (audit §1-2): the five heading sizes
   that comparison table showed -- 44-86 / 36-58 / 38-68 / 30-44 / 24-32,
   each picked independently, no shared scale -- collapse to three real
   tiers used consistently everywhere. Display stays unique to the one
   actual product hero below; every other screen's own title uses H1;
   every subordinate section title uses H2. Values are the best of what
   already existed, not new numbers -- this is consolidation, not a
   redesign. */
/* line-height/letter-spacing corrected 2026-09-20: measured live
   against TV's own real h1 (72px/weight 500/line-height 74.88px/
   letter-spacing -1.5px, i.e. a ~1.04 ratio and ~-0.021em) -- this
   rule's own prior values (0.98, -0.045em) were more than double TV's
   real negative tracking, tighter than TV actually sets it. */
h1 { max-width: 760px; margin-bottom: 28px; font: 500 clamp(48px, 6vw, 80px)/1.04 var(--serif); letter-spacing: -0.021em; }
h1 em { color: var(--terracotta); font-style: italic; }
/* Corrected 2026-09-20: TV's own real hero paragraph measures 21px
   with a 1.55 line-height ratio, in its real --ink-secondary color, not
   this rule's prior hardcoded #5e5a52 (a fourth, untokenized muted
   shade) at a smaller 17px. */
.hero-lede { max-width: 580px; color: var(--ink-secondary); font-size: 21px; line-height: 1.55; }
.choice-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 42px; max-width: 760px; }
.path-card { position: relative; min-height: 184px; padding: 22px; border: 1px solid var(--line); background: rgba(255, 253, 249, 0.54); color: var(--ink); text-align: left; transition: 180ms ease; }
.path-card:hover { border-color: var(--terracotta); transform: translateY(-3px); box-shadow: var(--shadow); }
.path-card-primary { background: var(--ink); color: var(--cream); border-color: var(--ink); }
.path-card-primary .path-kicker, .path-card-primary .arrow { color: #e59c84; }
.path-card strong { display: block; margin: 18px 0 10px; font: 500 24px var(--serif); }
.path-card > span:not(.path-kicker):not(.arrow) { display: block; max-width: 220px; color: inherit; opacity: 0.7; font-size: 13px; line-height: 1.45; }
.arrow { position: absolute; right: 22px; bottom: 20px; color: var(--terracotta); font-size: 22px; }
.hero-note { border-left: 1px solid var(--line-strong); padding-left: 22px; color: var(--ink-secondary); }
.note-number { color: var(--terracotta); font: 11px var(--mono); }
.hero-note p { margin: 8px 0 18px; font: 18px/1.25 var(--serif); color: var(--ink); }
.note-rule { height: 1px; background: var(--line); margin: 0 0 19px; }
.front-door-footer { display: flex; flex-wrap: wrap; gap: 26px; margin-top: 90px; color: var(--muted); font: 11px var(--mono); text-transform: uppercase; letter-spacing: 0.04em; }
.front-door-footer span::before { content: "+"; color: var(--sage); margin-right: 7px; }

.workspace-head, .blueprint-head { display: flex; justify-content: space-between; align-items: end; gap: 30px; border-bottom: 1px solid var(--line); padding-bottom: 24px; }
.workspace-head-actions { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
/* H1 tier: every screen's own title (Idea Desk, Council, Your projects,
   Your sessions, the book blueprint, the manuscript). #project-home-title
   keeps its own smaller, wrap-friendly rule below -- it routinely holds
   a full sentence, not a short name, a genuinely different case already
   handled deliberately, not overlooked here. */
/* line-height/letter-spacing corrected 2026-09-20: measured live
   against TV's own real h2 (36px/weight 500/line-height 41.4px/
   letter-spacing -0.5px, i.e. a ~1.15 ratio and ~-0.014em). */
.workspace h2, .blueprint h2, .conversation-column h2, .institute-card h2 { margin: 12px 0 8px; font: 500 clamp(36px, 5vw, 56px)/1.15 var(--serif); letter-spacing: -0.014em; }
.workspace-head p, .blueprint-head p { margin: 0; color: var(--ink-secondary); }

/* Caught in a design audit: #project-home-title had no rule of its own
   at all, so it silently fell back to the browser's bare h2 default
   (bold Inter, no serif treatment) while every other screen's heading
   got the deliberate serif/clamp treatment above. It also now often
   holds a full Claim sentence (renderProjectHome prefers home.thesis
   over the Project's own raw title, see that function's own comment),
   not a short name, so it's sized to read comfortably across 1-3 lines
   rather than as a single short display line. */
#project-home-title { margin: 10px 0 0; font: 500 clamp(26px, 3.4vw, 38px)/1.28 var(--serif); letter-spacing: -0.015em; max-width: 44ch; }
/* Caught live: showScreen() focuses every screen's own h2 on navigation
   (for screen-reader users), which triggers the shared h1/h2/h3
   focus-visible outline (6px offset) elsewhere in this file. That
   outline was sized for the short, single-line titles every other
   screen has; this heading now often wraps to 3-4 lines (it shows the
   full Claim, see this element's own JS-side comment), so the outline's
   bottom edge needs real clearance from whatever sits below it, not the
   same tight gap a one-line title could get away with. */
/* #id, not .class: .workspace-head p (below) sets margin:0 on every
   paragraph in this header, at higher specificity (class+tag beats one
   class) than a plain .project-home-status-line rule could override --
   found live by actually inspecting computed styles, not guessed at
   after the first fix silently did nothing. */
#project-home-status-line { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 30px 0 0; font-size: 13px; }
.project-home-status-line #project-home-claim-key { font: 600 11px var(--mono); color: var(--terracotta-dark); }
.project-home-status-line strong { color: var(--ink); font-weight: 600; }
.project-home-status-line .character-note { color: var(--muted); }

/* The one dominant action on the page (spec/16's own "one contextual
   CTA, not a dashboard") -- promoted directly under the header and
   given real visual weight (tint, border, a larger button) instead of
   competing on equal footing with the detail section below it. */
.next-move-hero { margin-top: 32px; padding: 26px 28px; border-radius: var(--radius); background: linear-gradient(135deg, rgba(194, 94, 58, 0.1), rgba(194, 94, 58, 0.03)); border: 1px solid rgba(194, 94, 58, 0.24); }
.next-move-hero .reason-label { display: block; margin-bottom: 12px; }
.next-move-hero .primary-button { min-height: 52px; padding: 0 26px; font-size: 14px; }
.next-move-hero .outline-button { margin-top: 12px; }

/* Everything that isn't the headline or the next move -- Qualification,
   Evidence, Artifacts, Book state, What changed -- grouped as one
   visually subordinate unit instead of five independent, equally-weighted
   boxes. A quiet divider marks it as "detail," not "more of the same." */
.project-home-detail { margin-top: 44px; padding-top: 6px; border-top: 1px solid var(--line); }
/* Real fix, not just relocation: caught live on a second screenshot --
   grouping the old .reason-box treatment (beige fill, orange left
   border, same weight as the Next-move hero above) under one divider
   didn't actually change anything about how loud each individual
   section reads. .reason-box's callout styling is reserved for things
   that earn it (the recommendation screen's own real alerts); these are
   reference lists, so they get a plain label and real spacing instead,
   no card chrome, no double-boxing when a row list sits inside one. */
.detail-section { margin-top: 34px; }
.detail-section:first-child { margin-top: 22px; }
.detail-section > .reason-label { display: block; margin-bottom: 12px; }
.detail-section .character-note { margin: 4px 0 0; }
/* "What changed" specifically: collapsed by default (same <details>
   pattern already used for "Add evidence"/"Create artifact" elsewhere
   on this page), and its own rows render compact -- one line each, not
   a full card -- since this is meant to be a quick glance, not a
   restatement of the Evolution screen's own full timeline. */
.detail-section .recommendation-detail { border-top: 0; padding-top: 0; }
.detail-section .recommendation-detail summary { padding: 0; color: var(--terracotta); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.12em; }
.detail-section .recommendation-detail summary:hover { color: var(--terracotta-dark); }
.detail-section .recommendation-detail[open] summary { margin-bottom: 12px; }
.events-list-compact { gap: 0; }
.event-row-compact { display: flex; align-items: baseline; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--line); font-size: 13px; }
.event-row-compact:first-child { padding-top: 0; }
.event-row-compact strong { font-weight: 500; color: var(--ink); }
.event-row-compact span { color: var(--muted); font: 11px var(--mono); white-space: nowrap; }
.desk-grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 24px; margin-top: 30px; }
.input-panel, .desk-aside, .emerging-panel, .room-brief, .workshop-input { border: 1px solid var(--line); background: var(--surface); box-shadow: 0 12px 32px rgba(71, 52, 37, 0.04); }
.input-panel { min-height: 430px; padding: 25px; }
/* Generalized 2026-09-20 from a single book-goal checkbox into a 3-way
   session-goal radio choice (sql/016_session_goal.sql's own comment on
   why) -- fieldset/legend reset to plain block styling, matching this
   app's own no-default-browser-chrome look everywhere else, with the
   three .book-goal-toggle rows (unchanged, still shared with any code
   that reads that class name) stacked directly beneath it. */
.session-goal-picker { border: 0; margin: 0 0 20px; padding: 0; }
.session-goal-picker legend { padding: 0 0 10px; color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; }
.book-goal-toggle { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px; padding: 14px 16px; background: var(--paper-deep); }
.book-goal-toggle:last-child { margin-bottom: 20px; }
.book-goal-toggle input { margin-top: 3px; }
.book-goal-toggle strong { display: block; color: var(--ink); font: 600 13px var(--sans); }
.book-goal-toggle small { display: block; margin-top: 3px; color: var(--muted); font-size: 12px; line-height: 1.5; }
.input-tabs { display: flex; gap: 20px; border-bottom: 1px solid var(--line); margin-bottom: 22px; }
.input-tab { padding: 0 0 12px; border: 0; border-bottom: 2px solid transparent; background: transparent; color: var(--muted); font-size: 13px; }
.input-tab.active { border-color: var(--terracotta); color: var(--ink); }
.input-mode.hidden { display: none; }
textarea { width: 100%; resize: vertical; border: 1px solid var(--line); background: var(--cream); color: var(--ink); padding: 16px; line-height: 1.6; }
textarea::placeholder { color: #aaa198; }
/* app.js grows these two to fit live dictation instead of hiding most of
   it below a fixed-height box. Capped here so a very long answer scrolls
   internally instead of growing the page indefinitely. */
#speak-input, #reply-input, #upload-input { max-height: 320px; overflow-y: auto; }
.input-footer, .reply-footer { display: flex; justify-content: space-between; align-items: center; gap: 14px; margin-top: 15px; }
/* --ink-secondary, not --muted, as of 2026-09-20: this class is this
   app's general-purpose descriptive-prose note (subtitles, inline
   explanations), the TV role its real, darker body-copy color fills --
   --muted itself stays correct for genuine small eyebrow-style labels
   elsewhere (see :root's own comment on why these are two different
   colors on TV, not one). .project-home-status-line's own override
   just below deliberately keeps --muted, since that one specific
   context is a status label, not prose. */
.character-note { color: var(--ink-secondary); font-size: 12px; }
.primary-button, .outline-button { min-height: 44px; padding: 0 18px; border-radius: var(--radius); font-size: 12px; }
/* Caught in a design audit: white text on plain --terracotta at this
   button's own 12px measures 4.24:1, below the 4.5:1 WCAG AA floor for
   text that size. --terracotta-dark (already this button's own hover
   shade, so nothing new to invent) measures 6.12:1 -- using it as the
   default, not just the hover state, clears the failure without
   changing the palette. Hover gets its own, still-darker shade instead
   of losing its own visual feedback. */
.primary-button { border: 1px solid var(--terracotta-dark); background: var(--terracotta-dark); color: white; }
.primary-button:hover { background: var(--terracotta-darker); border-color: var(--terracotta-darker); }
.primary-button:disabled, .outline-button:disabled { cursor: not-allowed; opacity: 0.45; }
.primary-button:disabled:hover { background: var(--terracotta-dark); border-color: var(--terracotta-dark); }
.outline-button:disabled:hover { border-color: var(--line-strong); color: var(--ink); }
.outline-button { border: 1px solid var(--line-strong); background: transparent; color: var(--ink); }
.outline-button:hover { border-color: var(--terracotta); color: var(--terracotta-dark); }

/* Voice recorder. State (idle vs recording) is carried by the icon's
   shape, not color or motion, so it survives prefers-reduced-motion and
   color-vision differences. See voice-recorder.js for the reasoning. */
.voice-recorder-mount { margin-bottom: 16px; }
.voice-recorder-button { display: flex; align-items: center; gap: 14px; width: 100%; min-height: 44px; border: 1px solid var(--line); background: var(--cream); color: var(--ink); padding: 16px 20px; text-align: left; }
.voice-recorder-button:hover { border-color: var(--terracotta); }
.voice-recorder-button.is-recording { border-color: var(--terracotta); background: var(--surface); }
.voice-recorder-button:disabled { cursor: not-allowed; opacity: 0.6; }
.voice-recorder-icon { display: grid; place-items: center; flex: 0 0 auto; width: 44px; height: 44px; border: 1px solid var(--terracotta); color: var(--terracotta); }
.voice-recorder-button.is-recording .voice-recorder-icon { background: var(--terracotta); color: var(--cream); }
.voice-recorder-copy { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.voice-recorder-label { font: 500 15px var(--serif); color: var(--ink); }
.voice-recorder-sub { font: 11px var(--mono); color: var(--muted); letter-spacing: 0.04em; }
.voice-recorder-button.is-recording .voice-recorder-sub { color: var(--terracotta-dark); }
.voice-recorder-notice { margin-top: 10px; color: var(--terracotta-dark); font-size: 12px; line-height: 1.5; }

.voice-recorder-compact .voice-recorder-button { min-height: 44px; padding: 8px 14px; gap: 10px; border-color: var(--line-strong); background: transparent; }
.voice-recorder-compact .voice-recorder-icon { width: 32px; height: 32px; }
.voice-recorder-compact .voice-recorder-sub { display: none; }
.voice-recorder-compact .voice-recorder-label { font: 500 13px var(--sans); }

/* Same visual language as .voice-recorder-button: bordered box, icon,
   label plus sub-copy. Dashed border distinguishes "choose a file" from
   the recorder's solid-bordered "start an action" affordance. */
.upload-dropzone { margin-bottom: 16px; }
.upload-label { display: flex; align-items: center; gap: 14px; width: 100%; min-height: 44px; padding: 16px 20px; border: 1px dashed var(--line-strong); background: var(--cream); color: var(--ink); cursor: pointer; }
.upload-label:hover { border-color: var(--terracotta); }
.upload-icon { display: grid; place-items: center; flex: 0 0 auto; width: 44px; height: 44px; border: 1px solid var(--terracotta); color: var(--terracotta); }
.upload-label strong { display: block; font: 500 15px var(--serif); color: var(--ink); }
.upload-label small { display: block; margin-top: 4px; font: 11px var(--mono); color: var(--muted); letter-spacing: 0.04em; }

.desk-aside { padding: 25px; background: var(--paper-deep); box-shadow: none; }
.starter-list { margin: 18px 0 40px; padding: 0; list-style: none; }
.starter-list li { padding: 13px 0; border-bottom: 1px solid rgba(198, 187, 171, 0.7); color: var(--ink-secondary); font: 16px/1.3 var(--serif); }
.privacy-note { display: flex; gap: 10px; color: var(--ink-secondary); font-size: 12px; line-height: 1.5; }
.privacy-icon { display: grid; place-items: center; flex: 0 0 auto; width: 19px; height: 19px; border: 1px solid var(--sage); color: var(--sage); font: 12px var(--mono); }

.session-bar { display: flex; justify-content: space-between; align-items: center; padding-bottom: 20px; border-bottom: 1px solid var(--line); color: var(--muted); font: 11px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }
.live-dot { display: inline-block; width: 7px; height: 7px; margin-right: 7px; border-radius: 50%; background: var(--sage); }
.session-progress { margin-left: 14px; padding-left: 14px; border-left: 1px solid var(--line-strong); }
.council-layout { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 24px; margin-top: 34px; }
/* Font/letter-spacing now come from the shared H1 tier above; this
   screen's own extra bottom margin (more breathing room before the
   two-column layout starts) is a real, kept difference, not drift. */
.conversation-column h2 { margin-bottom: 30px; }
.transcript { min-height: 280px; padding: 24px; border: 1px solid var(--line); background: var(--surface); }
.turn { margin-bottom: 22px; }
.turn:last-child { margin-bottom: 0; }
.turn-label { margin-bottom: 7px; color: var(--muted); font: 10px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; }
.turn p { margin: 0; max-width: 620px; color: var(--ink); font: 18px/1.45 var(--serif); }
.turn.assistant p { color: var(--terracotta-dark); }
.turn-pending p { color: var(--ink-secondary); font-style: italic; }
.reply-box { margin-top: 14px; padding: 15px; border: 1px solid var(--line-strong); background: var(--cream); }
.reply-box textarea { border: 0; padding: 4px; background: transparent; outline: 0; }
.session-actions { display: flex; justify-content: space-between; align-items: center; margin-top: 17px; }
.wrap-progress { margin: 10px 0 0; text-align: right; }
/* Caught live: this held the only visible readiness signal and the live
   claim/observation, but sat in normal document flow, so it scrolled out
   of view along with everything above it the moment a conversation grew
   past one screen. Sticky within .council-layout's height, not the whole
   page, so it still stops scrolling once the conversation column itself
   ends. Desktop only, see the 800px override: a phone's viewport is too
   short to spend on a pinned panel while scrolling a transcript. */
.emerging-panel { align-self: start; padding: 24px; background: rgba(255, 253, 249, 0.78); position: sticky; top: 24px; max-height: calc(100vh - 48px); overflow-y: auto; }
.panel-heading { display: flex; justify-content: space-between; align-items: center; }
.gate-chip { padding: 6px 8px; background: var(--paper-deep); color: var(--muted); font: 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }
.gate-a { background: #dde6dc; color: #4f6650; }
.emerging-panel h3 { margin: 18px 0 28px; font: 500 25px/1.12 var(--serif); }
.emerging-field { padding: 15px 0; border-top: 1px solid var(--line); }
.emerging-field span { color: var(--muted); font: 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }
.emerging-field p { margin: 8px 0 0; color: var(--ink); font: 16px/1.35 var(--serif); }
.muted-field p { color: var(--ink-secondary); font-size: 14px; }
.panel-link { margin-top: 12px; padding: 0; border: 0; background: transparent; color: var(--terracotta-dark); font-size: 12px; }
/* Makes the grounding/quote-preservation guarantee visible where the user is
   actually typing, instead of leaving it a server-side safeguard nobody sees. */
.grounding-note { margin: 16px 0 0; padding-top: 14px; border-top: 1px dashed var(--line-strong); color: var(--ink-secondary); font-size: 12px; line-height: 1.5; }

.recommendation { max-width: 760px; }
.recommendation-top { display: flex; justify-content: space-between; align-items: center; }
/* Was clamp(34px, 5vw, 52px): sized for a short placeholder ("Verdict
   goes here"). Real verdicts are a full sentence with a subordinate
   clause (per recommendation.mjs's schema description, "one short, plain
   sentence," which in practice still runs 20-30 words). At hero scale
   that sentence alone filled the viewport above every actionable item on
   the screen, caught live from a real screenshot. Sized down to a strong
   subhead instead of a landing-page headline; still the most prominent
   text on this screen, just not competing with the front door's actual
   hero. */
/* H2 tier now (audit's consolidated scale) -- still deliberately below
   the H1 tier above for the exact reason already documented: a real
   verdict sentence at hero scale overwhelmed the screen. */
/* letter-spacing corrected 2026-09-20: matches the ~-0.014em ratio
   measured on both TV's real h2 and its real card heading, which
   happen to land close together (-0.0139em and -0.0136em) -- this
   rule's own prior -0.015em was already nearly right, kept close
   rather than force an artificial third value. line-height (1.3) was
   already reasonably close to TV's own 1.15-1.25 range and is left
   alone. */
.recommendation h2 { margin: 20px 0 14px; font: 500 clamp(28px, 3.5vw, 36px)/1.3 var(--serif); letter-spacing: -0.014em; }
.format-tag { margin: 0 0 36px; color: var(--muted); font-size: 13px; }
.format-tag strong { color: var(--terracotta-dark); font: 600 13px var(--serif); }

.polish-actions { margin-bottom: 36px; }
/* Direct user feedback, 2026-09-18: 2-4 fully-written-out polish actions
   competed for attention with no signal about which one mattered most.
   start-here holds exactly one (the model's own primaryActionIndex), so
   the counter/border treatment built for a list of several reads oddly
   applied to a single item -- no top border to butt against, and the
   leading "01" is redundant when there's nothing after it to count
   against. */
.polish-actions.start-here li { border-top: 0; padding-top: 4px; }
.polish-actions.start-here li::before { display: none; }
.polish-actions-note { margin: 6px 0 0; color: var(--ink-secondary); font: 13px/1.5 var(--sans); }
.polish-actions ol { margin: 14px 0 0; padding: 0; list-style: none; counter-reset: polish; }
.polish-actions li { counter-increment: polish; display: flex; align-items: flex-start; gap: 14px; padding: 15px 0; border-top: 1px solid var(--line); }
.polish-actions li::before { content: counter(polish, decimal-leading-zero); flex: 0 0 auto; margin-top: 3px; color: var(--terracotta); font: 600 12px var(--mono); }
.polish-content { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 12px; }
.polish-row { display: flex; align-items: flex-start; gap: 14px; }
.polish-row > span:last-child { color: var(--ink); font: 16px/1.4 var(--serif); }

/* Per direct feedback: a prose list read as homework with nothing to
   click. draftable actions get a real attempt at the work; the rest route
   back into the live conversation instead of dead-ending on this screen. */
.polish-controls { padding-left: 34px; }
.polish-controls .outline-button, .polish-controls .text-button { min-height: 36px; padding: 0 14px; }
.polish-draft-wrap { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.polish-draft-output { width: 100%; padding: 14px; border-left: 2px solid var(--terracotta); background: var(--paper-deep); }
.polish-draft-label { display: block; margin-bottom: 8px; color: var(--muted); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.06em; }
.polish-draft-output textarea { width: 100%; padding: 0; border: 0; background: transparent; color: var(--ink); font: 15px/1.5 var(--serif); resize: vertical; }
.polish-draft-output textarea:focus { outline: none; }

.quick-save { margin-bottom: 36px; }
.quick-save-note { margin: 6px 0 14px; color: var(--ink-secondary); font: 13px/1.5 var(--sans); }
.format-list { display: grid; gap: 10px; }
/* Project Home's artifact-type picker only: the Recommendation screen's
   own .format-list (destination choices) stays a deliberate single
   column -- those are the one real decision that screen exists for, and
   read better full-width. Direct user feedback here specifically,
   though: "create artifacts choices are still not cards" -- a single
   column of full-width bordered rows still reads as a list, not a card
   grid, even with the same .format-option styling. */
.format-list-grid { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
/* .format-option's default layout is a horizontal row (title/description
   left, CHOOSE/SELECTED mark right) sized for the Recommendation
   screen's full-width single column. At grid-card width that same row
   layout squeezes the mark against wrapped description text -- stack
   vertically instead, same shape .artifact-card already uses. */
.format-list-grid .format-option { flex-direction: column; align-items: flex-start; gap: 8px; }
.format-list-grid .format-mark { align-self: flex-end; }

.recommendation-detail { border-top: 1px solid var(--line); padding-top: 4px; }
.recommendation-detail summary { cursor: pointer; padding: 14px 0; color: var(--muted); font: 600 11px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }
.recommendation-detail summary:hover { color: var(--terracotta-dark); }
.recommendation-detail[open] summary { color: var(--ink); }
.reason-box { margin-top: 18px; padding: 20px; border-left: 2px solid var(--terracotta); background: var(--paper-deep); }
.reason-box p { margin: 10px 0 0; color: var(--ink-secondary); font-size: 14px; line-height: 1.55; }
.reason-box + .reason-box { margin-top: 20px; }

/* The session notes behind an artifact (2026-09-20, direct user
   feedback: "what is insight object here?"). Collapsed by default and
   styled as reference rather than content: this is the material the
   work is checked against, not the work. */
.session-notes { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--line-strong); }
.session-notes summary { cursor: pointer; color: var(--terracotta-dark); font: 600 11px var(--mono); text-transform: uppercase; letter-spacing: 0.06em; }
.session-notes summary:hover { color: var(--terracotta-darker); }
.session-notes[open] summary { margin-bottom: 14px; }
.session-notes dl { margin: 0; display: grid; gap: 12px; }
.session-notes dt { color: var(--muted); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }
.session-notes dd { margin: 5px 0 0; color: var(--ink-secondary); font: 15px/1.55 var(--serif); }

/* Revision cues (2026-09-20, direct user feedback: "users need to get
   revision cues or ideas"). Each open Critique is its own dismissible
   item, not one merged blob -- manual dismiss (direct user decision)
   means items drop out of this list one at a time as they're addressed,
   so they need to read as individually actionable from the start. */
.cue-item { padding: 14px 0; border-top: 1px solid var(--line); }
.cue-item:first-child { padding-top: 0; border-top: 0; }
.cue-item p { margin: 0 0 10px; color: var(--ink-secondary); font-size: 14px; line-height: 1.55; white-space: pre-wrap; }
.format-option { display: flex; align-items: center; justify-content: space-between; gap: 18px; width: 100%; padding: 18px; border: 1px solid var(--line); background: var(--surface); color: var(--ink); text-align: left; }
.format-option:hover, .format-option.selected { border-color: var(--terracotta); }
.format-option:disabled { opacity: 0.55; cursor: not-allowed; }
.format-option:disabled:hover { border-color: var(--line); }
.format-option-book { border-style: dashed; }
.format-option strong, .format-option small { display: block; }
.format-option strong { font: 18px var(--serif); }
.format-option small { margin-top: 6px; color: var(--muted); font-size: 11px; line-height: 1.4; }
.format-mark { flex: 0 0 auto; color: var(--terracotta); font: 10px var(--mono); text-transform: uppercase; }
.recommendation-actions-row { margin-top: 58px; padding-top: 20px; border-top: 1px solid var(--line); }
.recommendation-actions { display: flex; justify-content: flex-start; align-items: center; gap: 18px; }

.blueprint-body { display: flex; flex-direction: column; gap: 18px; margin: 30px 0 40px; }
.room-workshop { display: grid; gap: 14px; }
.room-brief, .workshop-input { padding: 25px; }
.room-brief h3 { margin: 12px 0 10px; font: 500 28px var(--serif); }
.room-brief > p { max-width: 620px; color: var(--ink-secondary); line-height: 1.55; }
.room-output { margin-bottom: 20px; }
.room-grounding-note { margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--line); color: var(--ink-secondary); font-size: 13px; line-height: 1.5; }
.room-accepted-note { margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--line); color: var(--sage); font: 600 13px var(--sans); }
.room-feedback { padding: 18px 25px; border: 1px solid var(--line); background: var(--paper-deep); }
.room-feedback textarea { width: 100%; padding: 0; border: 0; background: transparent; color: var(--ink); font: 14px/1.5 var(--sans); resize: vertical; }
.room-feedback textarea:focus { outline: none; }
.room-feedback textarea::placeholder { color: var(--muted); }
.workshop-input { display: flex; align-items: center; gap: 16px; }

.manuscript-list { display: flex; flex-direction: column; gap: 10px; margin-top: 30px; }
.manuscript-row { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 18px; border: 1px solid var(--line); background: var(--surface); }
.manuscript-row-main { display: flex; align-items: baseline; gap: 16px; min-width: 0; }
.manuscript-number { flex: 0 0 auto; color: var(--terracotta); font: 600 12px var(--mono); }
.manuscript-title { margin: 0; color: var(--ink); font: 18px var(--serif); }
.manuscript-status { flex: 0 0 auto; padding: 4px 10px; background: var(--paper-deep); color: var(--muted); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.06em; }
.manuscript-status.draft { background: rgba(185, 86, 62, 0.14); color: var(--terracotta-dark); }
.manuscript-status.accepted { background: rgba(104, 125, 104, 0.16); color: var(--sage); }
.topbar-identity { color: var(--muted); font-size: 12px; }

.login-screen { display: grid; place-items: center; min-height: 70vh; }
.login-card { max-width: 440px; width: 100%; padding: 40px; border: 1px solid var(--line); background: var(--surface); box-shadow: var(--shadow); }
/* H2 tier: a login card's own title doesn't need H1/hero prominence. */
.login-card h2 { margin: 12px 0 8px; font: 500 clamp(28px, 3.5vw, 36px)/1.2 var(--serif); letter-spacing: -0.014em; }
.login-card > p { color: var(--ink-secondary); font-size: 15px; line-height: 1.6; }
.login-form { display: flex; flex-direction: column; gap: 12px; margin: 24px 0 0; }
.login-form input { border: 1px solid var(--line); background: var(--cream); color: var(--ink); padding: 13px 14px; }
.login-form input:focus { outline: none; border-color: var(--terracotta); }
.login-form .primary-button { min-height: 44px; }
#login-message { margin: 16px 0 0; }

/* Phase 7: Project Home's "Add evidence" form, same field styling as
   .login-form input above, extended to select/textarea for this one form. */
.evidence-form { display: flex; flex-direction: column; gap: 12px; margin: 16px 0 0; }
.evidence-form label { display: flex; flex-direction: column; gap: 6px; font-size: 12px; color: var(--muted); }
.evidence-form input, .evidence-form select, .evidence-form textarea {
  border: 1px solid var(--line); background: var(--cream); color: var(--ink); padding: 13px 14px; font: inherit;
}
.evidence-form input:focus, .evidence-form select:focus, .evidence-form textarea:focus { outline: none; border-color: var(--terracotta); }
.evidence-form textarea { min-height: 70px; resize: vertical; }
.evidence-list { display: flex; flex-direction: column; gap: 10px; margin: 14px 0 0; }
.evidence-row { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px; background: var(--surface); }
.evidence-row-meta { color: var(--muted); font: 11px var(--mono); text-transform: uppercase; margin: 4px 0 0; }
/* Phase 9: Artifact rows are buttons now (they open the editor), reset to
   look and lay out exactly like the plain evidence-row div they extend. */
.artifact-row-open { display: block; width: 100%; text-align: left; cursor: pointer; font: inherit; }
.artifact-row-open:hover { border-color: var(--terracotta); }

/* Project Home's Artifacts section: direct user feedback, "I need card
   grid for the artifacts" -- a real grid, not a taller version of the
   same full-width stacked rows .evidence-row uses elsewhere.

   Generalized 2026-09-20 into .card-grid/.summary-card, direct user
   feedback auditing navigation/quality app-wide: "I would prefer a
   card based design throughout the app" -- the Projects list and
   Session history screens wanted the exact same shape (a title, a
   status badge, a meta line, in a clickable card) a third and fourth
   time, past the point where keeping this artifact-specific was still
   the simpler choice. .artifact-grid/.artifact-card are kept as their
   own selectors alongside the new generic ones, not renamed, so the
   one existing call site (renderArtifactList) is untouched. */
/* Widened 2026-09-20: direct user feedback on a real, populated Projects
   grid ("see how awkward the projects section look... we are better off
   with slightly bigger cards") -- at 220px, real claim-sentence titles
   (no short name exists to head them) wrapped to 4-5 uneven lines across
   a 4-column grid, reading as jagged rather than deliberate. 280px settles
   most claims into 2-3 lines instead. */
.artifact-grid, .card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px; margin: 14px 0 0; }
.artifact-card, .summary-card { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; width: 100%; border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; background: var(--surface); text-align: left; cursor: pointer; font: inherit; }
.artifact-card:hover, .summary-card:hover { border-color: var(--terracotta); }
.artifact-card strong, .summary-card strong { font: 18px var(--serif); }
/* Same reasoning as above: the claim sentence was the first thing read on
   each card, with its journey/status badges trailing underneath like a
   footnote -- the exact "no heading" gap the user named. .summary-card-badges
   promotes them to a real label row read before the sentence, the same
   eyebrow role .summary-card-badge's own uppercase-mono-terracotta styling
   already plays elsewhere in this file; .summary-card-meta now holds only
   the trailing count/time line. */
.summary-card-badges { display: flex; flex-wrap: wrap; gap: 6px; }
.summary-card-meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; color: var(--ink-secondary); font-size: 12px; }
.summary-card-badge { flex: 0 0 auto; padding: 3px 8px; border-radius: var(--radius); background: var(--paper-deep); color: var(--terracotta-dark); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.06em; }

/* Delete Project/Artifact (2026-09-20, direct user feedback: "I should be
   able to delete a project an artifact throughout"). .artifact-card and
   .summary-card are themselves real <button>s (their whole surface opens
   the thing); a delete control can't nest inside that button (invalid
   HTML, and would fire both handlers on one click), so each card is
   wrapped in a plain, non-interactive .card-slot and the delete button is
   a real sibling <button>, positioned into the card's own top-right
   corner. stretch/height:100% on both keeps the grid's own equal-row-height
   behavior (styles.css's .card-grid comment above) working with the extra
   wrapper level. */
.card-slot { position: relative; height: 100%; }
.card-slot > .artifact-card, .card-slot > .summary-card { height: 100%; padding-right: 68px; }
.card-delete { position: absolute; top: 14px; right: 14px; border: 0; background: transparent; padding: 2px 4px; color: var(--danger); font: 600 11px var(--sans); cursor: pointer; }
.card-delete:hover { color: var(--danger-dark); text-decoration: underline; }

/* Same-page double-click confirm, not window.confirm() -- see this file's
   own pendingWrapConfirmation comment (app.js) for why a native confirm()
   dialog is specifically distrusted here: it was caught not reliably
   stopping a destructive action when declined under real Chromium
   automation. wireConfirmingDelete (app.js) drives this text swap. */
.card-delete.confirming, .danger-button.confirming { text-decoration: none; font-weight: 700; }

.danger-button { border: 1px solid var(--danger); background: transparent; color: var(--danger); min-height: 44px; padding: 0 18px; border-radius: var(--radius); font-size: 12px; cursor: pointer; }
.danger-button:hover { border-color: var(--danger-dark); color: var(--danger-dark); }
.danger-zone { margin-top: 34px; padding-top: 24px; border-top: 1px solid var(--line); }

/* Project Home's "Create artifact" toggle: direct user feedback, "create
   artifact is too small for the user to pay attention" -- the same
   <summary> disclosure mechanism as every other collapsible section on
   this page, just styled to read as a real call-to-action button instead
   of a small uppercase text link, matching .primary-button's own look.
   Selector repeats the full .detail-section .recommendation-detail
   ancestry (not just .detail-cta-toggle alone) so it actually outweighs
   that shared summary rule's specificity rather than losing the cascade
   to it silently. */
/* Gestalt proximity: this <details> sat flush against the artifact grid
   above it (0px gap -- .detail-section .recommendation-detail zeroes
   border-top/padding-top), making the button read as belonging to the
   last card rather than being a page-level "add a new one" action.
   Direct user feedback, a screenshot of exactly this: "why a card has a
   create artifact button right below it which seems to indicate the two
   are connected." 24px sits deliberately between the grid's own 14px
   card-gap and .detail-section's 34px section-to-section gap -- enough
   daylight to read as its own group, not a whole new section. */
#project-home-artifacts-box .recommendation-detail { margin-top: 24px; }
.detail-section .recommendation-detail summary.detail-cta-toggle { list-style: none; display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px; border-radius: var(--radius); border: 1px solid var(--terracotta-dark); background: var(--terracotta-dark); color: white; font: 600 13px var(--sans); text-transform: none; letter-spacing: normal; cursor: pointer; }
.detail-section .recommendation-detail summary.detail-cta-toggle::-webkit-details-marker { display: none; }
.detail-section .recommendation-detail summary.detail-cta-toggle:hover { background: var(--terracotta-darker); border-color: var(--terracotta-darker); color: white; }
.detail-section .recommendation-detail[open] summary.detail-cta-toggle { margin-bottom: 16px; }

/* Phase 9: the Artifact editor -- a plain textarea (spec/15 #84's own
   editor decision, see IMPLEMENTATION_DECISIONS.md), not a rich editor
   library, laid out next to a Revisions sidebar. */
.artifact-editor-layout { display: grid; grid-template-columns: 2fr 1fr; gap: 24px; margin: 24px 0 0; align-items: start; }
.artifact-editor-main { display: flex; flex-direction: column; gap: 14px; }
.artifact-editor-textarea {
  min-height: 360px; resize: vertical; border: 1px solid var(--line); background: var(--cream); color: var(--ink);
  padding: 16px; font: 16px/1.6 var(--serif);
}
.artifact-editor-textarea:focus { outline: none; border-color: var(--terracotta); }

/* Lean Canvas (2026-09-20, direct user feedback: "we really need it for
   the lean canvas with color coding of the boxes that needs revision
   with mechanism to revise"). Ash Maurya's own layout, not a uniform
   3x3: Problem, UVP and Customer Segments are full-height columns,
   Solution/Key Metrics and Unfair Advantage/Channels stack inside
   theirs, and Cost/Revenue run along the bottom. A founder recognises
   this shape on sight -- a nine-cell grid in reading order would be a
   different artifact wearing the name.

   The grid position comes from each box's own data-key, not source
   order: source order is the reading order the drafting prompt uses
   (Problem -> Customer Segments -> UVP -> ...), which is deliberately
   not the spatial order, and keeping them independent means neither has
   to bend to the other. */
/* Caught live, 2026-09-20: the canvas first shipped inside
   .artifact-editor-layout's 2fr column, which made each of five boxes
   146px wide -- labels collided with their own state flags and no box
   held a readable line. A canvas is a wide artifact; the Revisions rail
   that sits beside a textarea has to go underneath one instead. */
.artifact-editor-layout.is-canvas { grid-template-columns: minmax(0, 1fr); }
/* Underneath a canvas the Revisions rail is no longer a rail: its
   cards lay out as a row, not a tall stack down an empty column. */
.artifact-editor-layout.is-canvas .artifact-editor-side {
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 10px; padding-top: 24px; border-top: 1px solid var(--line);
}
.artifact-editor-layout.is-canvas #artifact-revisions-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px;
}

.lean-canvas {
  display: grid; gap: 10px; grid-template-columns: repeat(5, minmax(0, 1fr));
  grid-template-areas:
    "problem solution uvp    unfair   segments"
    "problem metrics  uvp    channels segments"
    "cost    cost     cost   revenue  revenue";
}
.canvas-box[data-key="problem"] { grid-area: problem; }
.canvas-box[data-key="solution"] { grid-area: solution; }
.canvas-box[data-key="key_metrics"] { grid-area: metrics; }
.canvas-box[data-key="unique_value_proposition"] { grid-area: uvp; }
.canvas-box[data-key="unfair_advantage"] { grid-area: unfair; }
.canvas-box[data-key="channels"] { grid-area: channels; }
.canvas-box[data-key="customer_segments"] { grid-area: segments; }
.canvas-box[data-key="cost_structure"] { grid-area: cost; }
.canvas-box[data-key="revenue_streams"] { grid-area: revenue; }

.canvas-box {
  display: flex; flex-direction: column; gap: 9px; min-height: 172px; padding: 14px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
}
.canvas-box:focus-within { border-color: var(--terracotta); }
.canvas-box-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 10px; }
.canvas-box-label { margin: 0; color: var(--muted); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }
.canvas-box-flag { margin-left: auto; color: var(--muted); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.06em; }
/* Height is set by app.js from the text's own scrollHeight (see
   autoGrow there): a Lean Canvas box is read at a glance, so a box that
   silently scrolls its own second half out of sight defeats the point of
   the format. overflow hidden, not auto, because the element is always
   exactly as tall as its content -- a scrollbar would only ever be a
   rendering artifact mid-resize. */
.canvas-box-text {
  flex: 1 1 auto; min-height: 84px; padding: 0; border: 0; background: transparent;
  color: var(--ink); font: 15px/1.5 var(--serif); resize: none; overflow: hidden;
}
.canvas-box-text:focus { outline: none; }
/* The placeholder is this box's own drafting guidance, so it's set in
   the UI font at label size -- it's instruction, not draft prose, and
   shouldn't masquerade as content in the serif the real text uses. */
.canvas-box-text::placeholder { color: var(--muted); font: 12px/1.45 var(--sans); }
.canvas-box-note { margin: 0; }
.canvas-box-actions, .cue-item-actions { display: flex; gap: 16px; }
/* 6px, not .text-button's own 7px and not the 0 this first shipped
   with: zero padding left a 14px-tall hit area inside a box already
   tight on vertical space, half of what every other text button in
   this app offers. */
.canvas-box-actions .text-button, .cue-item-actions .text-button { padding: 6px 0; }
/* Direct user feedback, 2026-09-20: "maybe critique CTA could be in a
   different colour" -- .text-button's default --muted made the one
   action every box always offers read as disabled label text rather
   than something to click. --terracotta-dark is this app's existing
   quiet-action colour (.panel-link already uses exactly this), not a
   new one, and it measures 6.12:1 on this surface at 12px, clear of
   the AA floor that --terracotta itself fails.
   Deliberately not applied to every button in the box: Critique and
   "Revise this box" are the real actions, while "Mark addressed" and
   "Undo revise" stay muted as the dismissals they are -- hierarchy
   within the box, not uniform emphasis. */
.canvas-action { color: var(--terracotta-dark); font-weight: 600; }
.canvas-action:hover { color: var(--terracotta-darker); }
.canvas-box-cues:empty { display: none; }
.canvas-box-cues .cue-item { padding: 10px 0; }
.canvas-box-cues .cue-item p { font-size: 13px; }
/* A cue the box has outgrown. Faded rather than hidden: it is still a
   real observation the user hasn't dismissed, just no longer a
   description of what's in front of them. */
.cue-item-stale p { color: var(--muted); }
.cue-item-stale .cue-stale-note { margin: 0 0 8px; font: italic 12px/1.5 var(--serif); }

/* The two states the colour rule names. Amber = an open revision cue on
   this box. Dashed and unfilled = honestly nothing established here yet
   -- drawn as an absence rather than a warning, because an empty
   Unfair Advantage on an early canvas is an accurate answer, not a
   failure. Both carry a text flag as well as a colour: the state has to
   survive a colour-vision difference and a grayscale screenshot, the
   same reasoning .voice-recorder-button's shape-not-colour state
   already follows. */
.canvas-box.needs-revision { border-color: var(--amber); background: rgba(184, 134, 46, 0.07); }
.canvas-box.needs-revision .canvas-box-flag { color: var(--amber-dark); }
.canvas-box.not-established { border-style: dashed; background: transparent; }

/* A box holding an unadopted proposal (2026-09-20, direct user feedback:
   "AI should help fix the gap"). Dashed like .not-established, because
   it is the same family of thing -- not yet the user's own -- and never
   solid, which is reserved for text they stand behind. It composes with
   .needs-revision rather than competing: that rule sets border-COLOR and
   background, this one sets border-STYLE, so a proposed box that still
   carries its originating cue reads as both at once. */
.canvas-box.proposed { border-style: dashed; }
.canvas-box-proposal {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 14px;
  padding: 10px 0 0; border-top: 1px dashed var(--line-strong);
}
.canvas-box-proposal p {
  margin: 0; color: var(--ink-secondary); font: italic 13px/1.5 var(--serif);
}
.canvas-box-proposal .text-button { padding: 0; }

/* The conversation panel (sql/021). The canvas keeps its own column and
   simply narrows: the exchange is about how one box affects the others,
   so hiding them behind a modal would remove the reason the panel
   exists. The Revisions rail drops below both. */
.artifact-editor-layout.is-canvas.thread-open {
  grid-template-columns: minmax(0, 1fr) 380px;
}
.artifact-editor-layout.is-canvas.thread-open .artifact-editor-main { grid-column: 1; grid-row: 1; }
.artifact-editor-layout.is-canvas.thread-open .thread-panel { grid-column: 2; grid-row: 1; }
.artifact-editor-layout.is-canvas.thread-open .artifact-editor-side { grid-column: 1 / -1; grid-row: 2; }
/* Caught live: the panel takes 380px, which left the canonical
   five-column layout rendering at ~140px a box -- the same unreadable
   squeeze that made this canvas full-width in the first place. While a
   conversation is open the canvas falls back to plain reading order,
   for the reason already given at the 1200px breakpoint: two readable
   columns beat a compressed pretence of the real layout. It returns to
   the Maurya grid the moment the panel closes. */
.artifact-editor-layout.is-canvas.thread-open .lean-canvas {
  grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-areas: none;
}
.artifact-editor-layout.is-canvas.thread-open .canvas-box { grid-area: auto; }

.thread-panel {
  display: flex; flex-direction: column; gap: 14px; align-self: start;
  position: sticky; top: 24px; max-height: calc(100vh - 48px);
  padding: 18px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--paper-deep);
}
.thread-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.thread-head h3 { margin: 6px 0 0; font: 500 21px var(--serif); }
.thread-messages { display: flex; flex-direction: column; gap: 16px; overflow-y: auto; }
.thread-turn-who { color: var(--muted); font: 600 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }
.thread-turn p { margin: 6px 0 0; color: var(--ink); font: 15px/1.55 var(--serif); white-space: pre-wrap; }
/* The user's own turns sit in the paper colour the canvas boxes use, so
   the transcript reads as their words against the panel, not as two
   voices in the same undifferentiated column. */
.thread-turn-human { padding: 12px 14px; border-radius: var(--radius); background: var(--surface); }
.thread-turn-human p { color: var(--ink-secondary); }
.thread-candidate {
  display: flex; flex-direction: column; gap: 10px; align-items: flex-start;
  padding-top: 14px; border-top: 1px dashed var(--line-strong);
}
.thread-candidate textarea {
  width: 100%; min-height: 96px; padding: 12px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--cream); color: var(--ink); font: 15px/1.5 var(--serif); resize: vertical;
}
.thread-candidate textarea:focus { outline: none; border-color: var(--terracotta); }
.thread-compose { display: flex; flex-direction: column; gap: 10px; padding-top: 14px; border-top: 1px solid var(--line); }
.thread-compose textarea {
  min-height: 84px; padding: 12px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--cream); color: var(--ink); font: 15px/1.5 var(--sans); resize: vertical;
}
.thread-compose textarea:focus { outline: none; border-color: var(--terracotta); }
.thread-compose-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

/* The box being discussed, and a box the conversation has just raised a
   cue on. Both are pointers, not states -- they say where to look right
   now, and neither survives closing the panel. */
.canvas-box.in-conversation { border-color: var(--terracotta); background: rgba(194, 94, 58, 0.05); }
.canvas-box.just-flagged { box-shadow: 0 0 0 2px rgba(184, 134, 46, 0.35); }

@media (max-width: 1200px) {
  /* Below this, five columns squeeze each box to a few words per line
     and the canonical layout stops being readable -- two columns in
     plain source (reading) order is the honest fallback, not a
     compressed pretence of the real thing. */
  .lean-canvas { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-areas: none; }
  .canvas-box { grid-area: auto !important; }
  /* No room for a side-by-side conversation at this width: the panel
     takes the full column and the canvas sits above it, still scrollable
     rather than hidden. */
  .artifact-editor-layout.is-canvas.thread-open { grid-template-columns: minmax(0, 1fr); }
  .artifact-editor-layout.is-canvas.thread-open .thread-panel {
    grid-column: 1; grid-row: 2; position: static; max-height: none;
  }
  .artifact-editor-layout.is-canvas.thread-open .artifact-editor-side { grid-row: 3; }
}
@media (max-width: 700px) {
  .lean-canvas { grid-template-columns: minmax(0, 1fr); }
}
.artifact-editor-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.artifact-editor-toolbar .character-note { margin: 0 auto 0 0; }
.artifact-editor-side { display: flex; flex-direction: column; gap: 4px; }
.artifact-revision-preview { white-space: pre-wrap; font: 13px/1.6 var(--mono); margin: 8px 0; max-height: 320px; overflow-y: auto; }
@media (max-width: 900px) {
  .artifact-editor-layout { grid-template-columns: 1fr; }
}

/* Phase 11: the Evolution screen's Idea Version compare selects, same
   field styling as .evidence-form, just flush with the sidebar's own
   top edge instead of carrying that form's usual top margin. */
.evolution-compare-selects { margin-top: 0; }

.institute { display: grid; place-items: center; min-height: 70vh; }
.institute-card { max-width: 650px; padding: 48px; border: 1px solid var(--line); background: var(--surface); box-shadow: var(--shadow); }
/* Corrected 2026-09-20: matches TV's own real card-body copy (15px/1.6
   ratio, --ink-secondary), the closer real match for a paragraph
   inside a card than the hero's own larger lede size. */
.institute-card > p { color: var(--ink-secondary); font-size: 15px; line-height: 1.6; }
.institute-points { display: flex; flex-wrap: wrap; gap: 16px; margin: 28px 0 32px; color: var(--sage); font: 11px var(--mono); text-transform: uppercase; }
.toast { position: fixed; right: 22px; bottom: 22px; max-width: 300px; padding: 13px 16px; background: var(--ink); color: var(--cream); font-size: 12px; box-shadow: var(--shadow); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

@media (max-width: 800px) {
  .topbar { height: 64px; padding: 0 20px; }
  .powered-by { display: none; }
  .journey-stepper { padding: 14px 20px; }
  .journey-step-label { display: none; }
  .journey-step.current .journey-step-label { display: block; font-size: 12px; }
  .screen { width: min(100% - 32px, 620px); padding: 42px 0 50px; }
  .hero-grid, .desk-grid, .council-layout { grid-template-columns: 1fr; }
  .hero-grid { gap: 40px; }
  h1 { font-size: clamp(43px, 14vw, 68px); }
  .choice-row { grid-template-columns: 1fr; margin-top: 30px; }
  .hero-note { display: grid; grid-template-columns: auto 1fr; gap: 5px 12px; border-left: 0; border-top: 1px solid var(--line-strong); padding: 18px 0 0; }
  .hero-note p { margin: 0 0 8px; }
  .note-rule { display: none; }
  .front-door-footer { margin-top: 48px; gap: 11px 20px; line-height: 1.4; }
  .workspace-head, .blueprint-head { align-items: start; flex-direction: column; }
  /* No fixed-size override needed here anymore: the consolidated H1
     clamp(36px, 5vw, 56px) already floors at exactly 36px well before
     this breakpoint (5vw only exceeds 36px past 720px), so it was
     tuned for the old, wider per-screen ranges these two selectors used
     to have -- now redundant with the shared tier above. */
  .desk-aside { order: -1; }
  .council-layout { margin-top: 23px; }
  .emerging-panel { order: -1; position: static; max-height: none; }
  .transcript { min-height: 220px; }
  .recommendation-actions, .input-footer, .reply-footer { align-items: stretch; flex-direction: column; }
  .primary-button, .outline-button { width: 100%; }
  .session-actions { flex-direction: column; align-items: stretch; gap: 14px; }
  .text-button { text-align: left; }
  .institute-card { padding: 30px 23px; }
}
