of a page * * Attributes (all on the contents element except where noted): * wa-toc-element="contents" | "link" | "table" | "ix-trigger" * -- structural markers. Multiple * "table" elements are allowed * and each receives a TOC copy. * wa-toc-offsettop="" -- click-scroll offset only * (e.g. clear a fixed navbar) * wa-toc-offsetbottom="" -- shifts active line down * wa-toc-activeline="" -- where headings activate * during scroll. Default 33vh. * wa-toc-headings="" -- restrict which heading levels * are collected. Default h2..h6. * wa-toc-hideurlhash="true" -- suppress #hash on click * wa-toc-ancestoractive="true" -- mark ancestors active too * wa-toc-instance="" -- (on a shared parent) scopes * multiple TOCs on one page * * In-text directives (inside heading plain text, stripped at render): * [wa-toc-omit] -- exclude this heading * [wa-toc-h2] .. [wa-toc-h6] -- override heading level in * the TOC only * * Active state uses Webflow's native `.w--current` class so styling can be * configured directly in the Webflow Designer. */ (function () { 'use strict'; var ACTIVE_CLASS = 'w--current'; var ATTR = 'wa-toc-element'; var DIRECTIVE_RE = /\[wa-toc-(omit|h([2-6]))\]/i; var DEFAULT_HEADING_SELECTOR = 'h2, h3, h4, h5, h6'; // ---------- utilities -------------------------------------------------- /** * Slugify heading text into an id. Mirrors Webflow's native id generation * closely enough for hash navigation: lowercase, spaces 鈫 hyphens, drop * non-alphanumeric except hyphens, collapse runs of hyphens. */ function slugify(text) { return String(text) .toLowerCase() .trim() .replace(/[\s_]+/g, '-') .replace(/[^a-z0-9\-]/g, '') .replace(/-+/g, '-') .replace(/^-|-$/g, ''); } /** Ensure a slug is unique within a Set, suffixing -2, -3, ... if needed. */ function uniqueSlug(base, used) { if (!base) base = 'section'; var slug = base; var i = 2; while (used.has(slug)) { slug = base + '-' + i++; } used.add(slug); return slug; } /** * Convert a CSS length string (e.g. "8rem", "120px", "10vh") to pixels, * resolved against the document root. Returns 0 on failure. */ function cssLengthToPx(value) { if (!value) return 0; var probe = document.createElement('div'); probe.style.position = 'absolute'; probe.style.visibility = 'hidden'; probe.style.height = value; probe.style.width = '0'; document.body.appendChild(probe); var px = probe.getBoundingClientRect().height; document.body.removeChild(probe); return isFinite(px) ? px : 0; } /** * Parse the wa-toc-headings attribute into a CSS selector. Accepts: * "h2,h3" 鈫 "h2, h3" * "h2 h3 h4" 鈫 "h2, h3, h4" * "2,3" 鈫 "h2, h3" * "H2, h3" 鈫 "h2, h3" (case-insensitive) * Tokens outside h2..h6 are dropped. Returns the default selector when * the input is empty or yields no valid levels 鈥 keeps behavior safe. */ function parseHeadingLevels(raw) { if (!raw) return DEFAULT_HEADING_SELECTOR; var tokens = String(raw) .toLowerCase() .split(/[\s,]+/); var levels = []; var seen = {}; for (var i = 0; i < tokens.length; i++) { var tok = tokens[i].trim(); if (!tok) continue; // Accept "h2" or "2". var m = /^h?([2-6])$/.exec(tok); if (!m) continue; var tag = 'h' + m[1]; if (seen[tag]) continue; seen[tag] = true; levels.push(tag); } if (!levels.length) return DEFAULT_HEADING_SELECTOR; return levels.join(', '); } /** Find the closest ancestor (or self) carrying wa-toc-instance. */ function instanceOf(el) { var node = el; while (node && node.nodeType === 1) { if (node.hasAttribute('wa-toc-instance')) { return node.getAttribute('wa-toc-instance'); } node = node.parentElement; } return ''; // default unnamed instance } /** Find the link template within a given root, matching wa-toc-element="link". */ function findLinkTemplate(root) { return root.querySelector('[' + ATTR + '="link"]'); } /** * The link template may be applied directly to an , or to a text * element nested inside an . Resolve to the actual we should clone. */ function resolveAnchorTemplate(linkEl) { if (linkEl.tagName === 'A') return linkEl; var anchor = linkEl.closest('a'); return anchor || linkEl; // fall back to the marked element itself } /** * Within a cloned link, find the text-bearing element that originally had * wa-toc-element="link". If the marker was on the anchor itself, the * anchor is the text holder. */ function findTextHolder(clonedAnchor, originalMarker) { if (originalMarker.tagName === 'A') return clonedAnchor; // The marker was a descendant; find the same descendant in the clone by // walking the same path. var path = []; var node = originalMarker; var rootAnchor = originalMarker.closest('a'); while (node && node !== rootAnchor) { var parent = node.parentElement; if (!parent) break; path.unshift(Array.prototype.indexOf.call(parent.children, node)); node = parent; } var current = clonedAnchor; for (var i = 0; i < path.length; i++) { current = current.children[path[i]]; if (!current) return clonedAnchor; } return current; } // ---------- per-instance pipeline ------------------------------------- function buildInstance(contentsEl) { var instanceId = instanceOf(contentsEl); // Locate the link template in the same instance. var linkMarker = null; var allLinks = document.querySelectorAll('[' + ATTR + '="link"]'); for (var i = 0; i < allLinks.length; i++) { if (instanceOf(allLinks[i]) === instanceId) { linkMarker = allLinks[i]; break; } } if (!linkMarker) return null; // nothing to do var anchorTemplate = resolveAnchorTemplate(linkMarker); // Locate every wa-toc-element="table" in the same instance. The TOC will // be rendered into each one 鈥 same headings, same active-state tracking, // independent styling contexts. If none are present, fall back to a // single mount at the link template's parent (Finsweet-compatible). var mountEls = []; var allTables = document.querySelectorAll('[' + ATTR + '="table"]'); for (var j = 0; j < allTables.length; j++) { if (instanceOf(allTables[j]) === instanceId) { mountEls.push(allTables[j]); } } if (!mountEls.length) { var fallback = anchorTemplate.parentElement; if (!fallback) return null; mountEls.push(fallback); } // Read config off the contents element. var offsetTopVal = cssLengthToPx(contentsEl.getAttribute('wa-toc-offsettop')); var offsetBotVal = cssLengthToPx(contentsEl.getAttribute('wa-toc-offsetbottom')); var hideHash = contentsEl.getAttribute('wa-toc-hideurlhash') === 'true'; var ancestorMode = contentsEl.getAttribute('wa-toc-ancestoractive') === 'true'; var activeLineAttr = contentsEl.getAttribute('wa-toc-activeline'); var activeLineRaw = activeLineAttr; // keep raw for vh re-resolution on resize var headingSelector = parseHeadingLevels(contentsEl.getAttribute('wa-toc-headings')); // Collect heading elements in document order, applying directives. var rawHeadings = contentsEl.querySelectorAll(headingSelector); var headings = []; var usedIds = new Set(); for (var k = 0; k < rawHeadings.length; k++) { var h = rawHeadings[k]; var text = h.textContent || ''; var levelOverride = null; var omit = false; // Strip *all* directive occurrences from the rendered heading text and // capture the first relevant one. We also clear them from the live DOM // so readers don't see "[wa-toc-h4]My heading". var cleaned = text; var match; while ((match = DIRECTIVE_RE.exec(cleaned))) { if (match[1].toLowerCase() === 'omit') { omit = true; } else if (match[2]) { levelOverride = parseInt(match[2], 10); } cleaned = cleaned.slice(0, match.index) + cleaned.slice(match.index + match[0].length); } cleaned = cleaned.trim(); if (cleaned !== text) { // Replace directive markers in text nodes only, preserving inline // markup like / children. stripDirectivesInPlace(h); } if (omit || !cleaned) continue; // Assign / preserve id for hash linking. var id = h.id; if (!id) { id = uniqueSlug(slugify(cleaned), usedIds); h.id = id; } else { usedIds.add(id); } var actualLevel = parseInt(h.tagName.charAt(1), 10); var displayLevel = levelOverride || actualLevel; headings.push({ el: h, id: id, text: cleaned, level: displayLevel, }); } if (!headings.length) return null; // The TOC must start at H2. If somebody overrode levels, normalize so the // shallowest level encountered renders at the outermost nesting depth. var minLevel = headings.reduce(function (m, h) { return Math.min(m, h.level); }, 6); // Build the nested DOM. We need *wrappers* so children of an H# can be // appended next to (not inside) the link itself. Per Finsweet's docs: // "Each Heading link template must be enclosed in a div wrapper, and // this div wrapper should be a child of the div associated with the // preceding Heading level." // // We model this with a per-level "wrapper" element. The first child of // the wrapper is the link; subsequent children are nested wrappers. var rootContainer = document.createElement('div'); rootContainer.setAttribute('wa-toc-element', 'list'); var entries = []; // parallel array: { link, wrapper, heading } var stack = [{ level: minLevel - 1, wrapper: rootContainer }]; for (var n = 0; n < headings.length; n++) { var heading = headings[n]; // Pop until the top of stack is the parent level (one shallower). while (stack.length > 1 && stack[stack.length - 1].level >= heading.level) { stack.pop(); } var parentWrapper = stack[stack.length - 1].wrapper; // Build wrapper for this heading. var wrapper = document.createElement('div'); wrapper.setAttribute('wa-toc-element', 'h' + heading.level + '-wrapper'); // Clone the link template. var link = anchorTemplate.cloneNode(true); // Remove the marker attribute on the clone to avoid re-detection. var markersInClone = link.querySelectorAll('[' + ATTR + '="link"]'); for (var mi = 0; mi < markersInClone.length; mi++) { markersInClone[mi].removeAttribute(ATTR); } if (link.getAttribute(ATTR) === 'link') link.removeAttribute(ATTR); // Set the text on the resolved text holder. var holder = findTextHolder(link, linkMarker); holder.textContent = heading.text; // Set href and tag with entry index so we can find this same link // inside each cloned mount and wire it up. link.setAttribute('href', '#' + heading.id); link.setAttribute('data-wa-toc-idx', String(entries.length)); wrapper.appendChild(link); parentWrapper.appendChild(wrapper); entries.push({ heading: heading, // Filled in below: one cloned link per mount target. links: [], ixTriggers: [], }); stack.push({ level: heading.level, wrapper: wrapper }); } // Mount the built tree into every target. We clone for *every* mount // (including the first) so `rootContainer` stays intact across the loop // and serves as a clean source for each subsequent mount. Querying // inside each mount by data-wa-toc-idx lets us collect the per-mount // link nodes back into the corresponding entry. function mountInto(target, treeChildren) { while (target.firstChild) target.removeChild(target.firstChild); for (var c = 0; c < treeChildren.length; c++) target.appendChild(treeChildren[c]); // Pull this mount's links into entries. var mountedLinks = target.querySelectorAll('[data-wa-toc-idx]'); for (var ml = 0; ml < mountedLinks.length; ml++) { var idx = parseInt(mountedLinks[ml].getAttribute('data-wa-toc-idx'), 10); if (entries[idx]) entries[idx].links.push(mountedLinks[ml]); // Per Finsweet ix-trigger semantics: triggers live inside the link // template, fire on this entry's active transitions. var triggers = mountedLinks[ml].querySelectorAll('[' + ATTR + '="ix-trigger"]'); for (var tg = 0; tg < triggers.length; tg++) { entries[idx].ixTriggers.push(triggers[tg]); } } } for (var t = 0; t < mountEls.length; t++) { var cloned = rootContainer.cloneNode(true); var children = Array.prototype.slice.call(cloned.children); mountInto(mountEls[t], children); } // Strip the temporary index marker now that all mounts have been wired. for (var en = 0; en < entries.length; en++) { for (var lk = 0; lk < entries[en].links.length; lk++) { entries[en].links[lk].removeAttribute('data-wa-toc-idx'); } } // Click handling: smooth scroll, hash control. Listener runs in capture // phase and stops propagation so any external listener (e.g. Webflow's // own anchor handling, or a parent click handler on the link wrapper) // can't run a competing scroll. We also reread offsetTopVal on each // click in case the page has resized 鈥 vh-based offsets need this. function onLinkClick(entry, ev) { ev.preventDefault(); ev.stopPropagation(); var liveOffsetTop = cssLengthToPx(contentsEl.getAttribute('wa-toc-offsettop')); var targetTop = entry.heading.el.getBoundingClientRect().top + window.pageYOffset - liveOffsetTop; window.scrollTo({ top: targetTop, behavior: 'smooth' }); if (!hideHash) { if (history.replaceState) { history.replaceState(null, '', '#' + entry.heading.id); } else { location.hash = '#' + entry.heading.id; } } } entries.forEach(function (entry) { entry.links.forEach(function (link) { link.addEventListener( 'click', function (ev) { onLinkClick(entry, ev); }, true, ); }); }); return { contentsEl: contentsEl, entries: entries, offsetTop: offsetTopVal, offsetBottom: offsetBotVal, activeLineRaw: activeLineRaw, ancestorMode: ancestorMode, activeIndex: -1, previousIxState: new WeakMap(), }; } /** * Walk text nodes inside `el` and remove [wa-toc-omit] / [wa-toc-h#] markers * so they don't appear in the rendered page. */ function stripDirectivesInPlace(el) { var walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null); var node; var toFix = []; while ((node = walker.nextNode())) { if (DIRECTIVE_RE.test(node.nodeValue)) toFix.push(node); } toFix.forEach(function (n) { n.nodeValue = n.nodeValue.replace(/\[wa-toc-(omit|h[2-6])\]/gi, '').trim(); }); } // ---------- active-link tracking -------------------------------------- /** * Default active-line position when wa-toc-activeline isn't set. * 1/3 of viewport height 鈥 a heading activates as soon as it scrolls up * into the upper third of the viewport, while still comfortably visible. */ var DEFAULT_ACTIVE_LINE_FRACTION = 1 / 3; /** * Resolve the active-line position (in px from viewport top) for an * instance. wa-toc-activeline accepts any CSS length; if absent, falls * back to a fraction of viewport height. Recomputed on every call so * vh-based values track resizes naturally. */ function resolveActiveLine(instance) { if (instance.activeLineRaw) { var px = cssLengthToPx(instance.activeLineRaw); if (px > 0) return px; } var viewportH = window.innerHeight || document.documentElement.clientHeight; return viewportH * DEFAULT_ACTIVE_LINE_FRACTION; } /** * Determine which heading owns the viewport. * * Rule: the active heading is the *last* one whose top has crossed the * "active line" 鈥 a horizontal line in the viewport configured by * wa-toc-activeline (default: 1/3 of viewport height). * * `wa-toc-offsetbottom` extends the line further down 鈥 i.e. the previous * heading stays active until the next heading reaches `offsetBottom` past * the active line. * * Note: this is independent of `wa-toc-offsettop`, which only affects * smooth-scroll-on-click (so a fixed navbar can be cleared without * shifting where headings activate). * * Entries are scanned in document order and we take the maximum match * rather than break early, so the result is correct even if CSS reorders * elements relative to DOM order. * * Returns -1 when no heading has yet reached the active line. */ function computeActiveIndex(instance) { var entries = instance.entries; if (!entries.length) return -1; var threshold = resolveActiveLine(instance) + instance.offsetBottom; var active = -1; for (var i = 0; i < entries.length; i++) { // viewport-relative top of this heading var top = entries[i].heading.el.getBoundingClientRect().top; if (top <= threshold) { active = i; // keep the latest match 鈥 do NOT break } } return active; } /** * Apply active state. Always clears every link first so external sources * of `.w--current` (e.g. Webflow's URL-hash matching) can't leave stale * classes around. We don't early-out on `newIndex === activeIndex` for * that same reason 鈥 it's cheap to re-set and guarantees correctness. * * Each entry may have multiple link clones (one per mount target). The * active class is applied uniformly to all clones so every rendered TOC * stays in sync. */ function applyActive(instance, newIndex) { var entries = instance.entries; function setClass(entry, on) { for (var li = 0; li < entry.links.length; li++) { if (on) entry.links[li].classList.add(ACTIVE_CLASS); else entry.links[li].classList.remove(ACTIVE_CLASS); } } // Clear all. for (var i = 0; i < entries.length; i++) setClass(entries[i], false); if (newIndex >= 0 && newIndex < entries.length) { // Mark the directly-active entry. var activeEntry = entries[newIndex]; setClass(activeEntry, true); // Optionally mark ancestors. An ancestor of entry N is the most recent // earlier entry whose level is strictly shallower, walking up until we // run out of shallower levels. if (instance.ancestorMode) { var currentLevel = activeEntry.heading.level; for (var k = newIndex - 1; k >= 0 && currentLevel > 1; k--) { if (entries[k].heading.level < currentLevel) { setClass(entries[k], true); currentLevel = entries[k].heading.level; } } } } // Fire ix-trigger transitions only when the index actually changed. We // dispatch on every cloned trigger across all mounts so Webflow IX2 // animations run uniformly in each rendered TOC. if (newIndex !== instance.activeIndex) { for (var j = 0; j < entries.length; j++) { var entry = entries[j]; if (!entry.ixTriggers || !entry.ixTriggers.length) continue; // Read state from the first clone 鈥 they're kept in sync. var isActive = entry.links.length > 0 && entry.links[0].classList.contains(ACTIVE_CLASS); var was = instance.previousIxState.get(entry) === true; if (isActive !== was) { entry.ixTriggers.forEach(function (t) { t.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); }); instance.previousIxState.set(entry, isActive); } } instance.activeIndex = newIndex; } } // ---------- bootstrap -------------------------------------------------- function init() { var contentsEls = document.querySelectorAll('[' + ATTR + '="contents"]'); var instances = []; contentsEls.forEach(function (el) { var inst = buildInstance(el); if (inst) instances.push(inst); }); if (!instances.length) return; function update() { for (var i = 0; i < instances.length; i++) { applyActive(instances[i], computeActiveIndex(instances[i])); } } // Throttle to one update per frame. var ticking = false; function onScroll() { if (ticking) return; ticking = true; requestAnimationFrame(function () { update(); ticking = false; }); } window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); update(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();

成人VR视频

Skip to main content

The capacity question: What midsize law firms need to decide before they adopt AI

By:
Michelle Nesbitt-Burrell
July 23, 2026
Michelle Nesbitt-Burrell
,
September 8, 2026
September 8, 2026
12 min
This is some text inside of a div block.

Midsize law firms will only realize meaningful value from AI if they first decide how to strategically redeploy the lawyer capacity that AI creates, while simultaneously addressing the talent, client, and ROI challenges it creates.

Key takeaways

  • Most midsize law firms are investing in AI but have not answered the question that determines whether it creates value: How does freed-up lawyer capacity actually get deployed?
  • The biggest unrecognized talent risk from slow AI adoption sits with mid-career professionals, not junior lawyers. Almost 3-in-10 say they would change jobs within two years if AI fails to deliver.
  • The firms getting ahead are not the fastest movers; they鈥檙e the ones that answered the capacity question before adopting AI and started with a specific use case.

Picture the law firm that gets this right. Its mid-career lawyers spend less time on administrative overhead 鈥 organizing research, wading through documents, formatting contracts, and chasing down information 鈥 and more time on actual legal thinking, such as evaluating arguments, building strategy, and advising clients. This firm鈥檚 associates are building client relationships and developing a book of business three years earlier because they are doing substantive legal work earlier, not managing its logistics.

The firm鈥檚 fixed-fee matters are more profitable because efficiency gains go straight to margin 鈥 and when clients ask what the firm's AI investment has changed for them, there is a specific, evidenced answer.

That firm exists. The gap between it and most midsize law firms is not primarily about which AI tools they have chosen; it is about whether they have answered one question first. Unfortunately, most firms have not answered it yet.

The question is not which AI tool to buy, and it鈥檚 not how to make the business case to partners, or how to manage the billing conversation with clients. Those are real questions, of course, but they are all downstream of the one single question that determines whether any of it generates lasting value.

That question is: What does your firm do with the capacity that AI creates?

Freed capacity is not the same as strategic work

On the surface, the answer seems obvious. AI frees up lawyer time, and lawyers then use that time for more valuable work. As a result, the firm grows. In practice, however, it is considerably more complicated for reasons that go to the heart of how law firms are structured.

The work that AI is best at handling 鈥 such as research, document review, first-draft preparation, summarization 鈥 is also the work that has historically been the training ground for junior lawyers. It is the work through which associates build foundational legal skills, learn what good lawyering looks like, and earn the trust of partners.

Remove that work without replacing the developmental pathway it provided, and you have not just freed up capacity, you have restructured the pipeline through which the firm produces its next generation of senior lawyers. Ultimately, many firms are not yet ready to do that without much deeper consideration of how they operate.

The gap between it and most midsize law firms is not primarily about which AI tools they have chosen; it is about whether they have answered one question first: What does your firm do with the capacity that AI creates?

At the same time, freed capacity does not automatically become strategic work 鈥 rather, it becomes available time. What that time is deployed on depends entirely on whether firm leadership has made deliberate choices and communicated those choices clearly enough that partners and associates can act on them.

The firms that are furthest ahead on this are not necessarily the most technically sophisticated. They are the ones that made their intent explicit before they started. They began with a specific practice area, a specific work type, and a clear view of what they wanted the redeployed time to look like. The answer became visible from there.

Of course, this takes thoughtful consideration, because AI does not affect all work equally. If margin growth is the goal, for example, start with fixed-fee work where capacity is constrained.

Also, remember that AI should do more than simply automate your existing processes. Identify where AI can expand scale, quality and capability, then redesign workflows and deliverables accordingly. Only then should you determine what to charge for that work.

Recommended action: Ask your most senior practice group leaders to write one sentence describing what they want their lawyers to be doing more of once AI automates the repeatable work. If those sentences describe tasks rather than capabilities 鈥 such as more drafting rather than establishing client relationships earlier 鈥 then the capacity question has not yet been answered at the level that matters.

Three pressure points that make the question urgent now

This capacity question is not new; however, three pressure points have converged in 2026 to make the question significantly more urgent for midsize firms. These pressure points include:

1. Why clients instruct law firms, and how AI changes that calculus

Corporate legal departments instruct law firms for three reasons 鈥 capacity, capability, and coverage 鈥 and AI is disrupting all three in the following ways:

Capacity: Today, AI is making it easier for in-house teams to manage routine work, which means the volume of capacity-based work flowing to external firms will decline over time. The law firms that will be able to retain this work are those that can offer AI-enabled products and services that in-house teams cannot replicate themselves.

Capability: This is the value-add category. It depends on firms turning their collective expertise into actionable insight that clients cannot from AI tools or subscription services alone. The lawyers who deliver this are not reviewing documents; they are applying judgment, building strategy, and anticipating risks.

Coverage: Key clients always will want to outsource high-risk work, but that work is increasingly being disaggregated, with law firms providing final sign-off and strategic oversight rather than managing the entire workflow. Corporate budget pressure will accelerate this shift.

The implication is clear: Those law firms that will grow are those that can demonstrably deliver on capability and coverage, not just capacity. And the data confirms that clients already understand this. 成人VR视频 Future of Professionals 2026 report 鈥 drawing on responses from professionals across 62 countries 鈥 finds that 78% of corporate clients say receiving AI-enabled quality improvements from the firms they hire is very important or essential, while just 6% say most or all of their current providers are delivering it. Further, nearly one-third have already reconsidered or plan to reconsider their firm relationships as a result, with a portion of those estimating that more than $1 million dollars of annual work is at risk.

Recommended action: Ask your most senior practice group leaders two questions. First: where does AI save us the most time, and what do we do with that saving 鈥 more matters, better margin, or something else? Second: where could AI enable us to deliver something genuinely better or new 鈥 more thorough analysis, earlier risk identification, more consistent quality at scale 鈥 and what might that enhanced service justify charging? If the answers to both questions are vague, the capacity question has not yet been answered at the level that matters.

2. The talent risk you are probably not looking for

The conventional AI talent narrative focuses on junior lawyers, especially at midsize firms. That concern is real, but our research points to a more immediate and largely unrecognized risk.

The professionals most exposed to AI disruption are not junior lawyers, but rather mid-career professionals, who often are the heaviest AI users, the most influential in how work actually gets done, and the clearest judges of the gap between AI鈥檚 potential and its current impact. Critically, they also are the most mobile and the hardest to replace, a concern many midsize firms share.

Indeed, almost 3-in-10 mid-career professionals across all professional services say they will change jobs within two years if AI fails to give them the right tools, training, or adoption pace to make AI work as it should. Further, 14% say they would consider leaving their current firm within the next 12 months if they do not see AI giving them the benefits they seek. This mindset does not yet show up as an AI signal in most firms' engagement or exit data; however, it does show up as dissatisfaction or departure and often gets labelled as something else.

Ask where does AI save us the most time, and what do we do with that saving 鈥 more matters, better margin, or something else?

The junior pipeline concern compounds this. When mid-career professionals leave, taking their mentorship capacity with them, the development of junior lawyers suffers at exactly the moment it most needs experienced oversight. If those two pressures coincide, the skills deficit builds quietly and doesn't show up until the lawyers who should be stepping into senior roles in five years are simply not ready.

Recommended action: Review your firm鈥檚 engagement and exit data from the last 12 months for mid-career professionals specifically. Is there a pattern that could be an AI signal, such as frustration with tool access, dissatisfaction with adoption pace, or departure to firms perceived as more advanced? If you do not know, that itself is a finding worth acting upon.

3. The investment is already happening, but the return is not yet visible

While law firms are increasingly investing in AI, there remains a striking gap between investment levels and firms' ability to demonstrate the benefits of AI. In fact, our research shows that only around 1-in-6 law firms currently measures their AI ROI.

Without such measurements, firms cannot make the value case to partners 鈥 or answer client who ask: What has your AI investment changed for us?

Yet, at its most basic level, freed capacity means more matters handled in the same time, reduced write-offs on work that was previously absorbing billable hours at low or zero realization, and improved margin on fixed-fee work. Those outcomes are measurable from day one, but only if a baseline exists.

There is also an underappreciated verification challenge. AI creates value only when the time saved exceeds the time required to review, validate, and stand behind the output. Firms that simply shift their efforts from production to verification may be overstating the value they capture.

Importantly, tools matter, because a system grounded in authoritative legal sources with clear citations reduces verification burdens in ways general-purpose tools do not.

Recommended action: Define at least one metric per AI-enabled workflow before you start 鈥 and if you can only track one thing initially, track write-off rate. It is the clearest early signal that AI is reducing the hidden cost of low-realization work and measuring it requires no change to your billing model. (See the metrics framework below for a starter and more sophisticated set of measures to build toward.)

Where to begin? Track write-off rate first. It requires no change to billing model, is measurable immediately, and is the clearest signal that AI is reducing the hidden cost of low-realization work.

What the capacity question is really asking

At its core, the capacity question is about the difference between efficiency and transformation.

An efficiency answer is straightforward: AI handles repetitive work, lawyers gain time, utilization improves, and margins expand. Yet, efficiency alone does not change what a law firm is, or what it can charge for the work it does. Passing on efficiency gains to clients in the form of lower fees, or failing to redeploy freed-up time toward higher-value work, means your firm will absorb the cost of AI without capturing its full potential.

A transformative answer goes further: AI handles repetitive work, and the firm uses the freed capacity and the enhanced capability to do things it could not previously do. This requires redesigning workflows to deliver more proactive advice, offer earlier risk identification, or devise richer client strategy 鈥 not simply automating existing processes.

After establishing this more transformative track, midsize firm leaders should think about pricing, specifically, what those redesigned workflows and new deliverables justify in rates charged.

TRI's Managing Partner research is specific about what this transformation looks like in practice. 聽Across 116 in-depth interviews with law firm leaders, four needs consistently came up:

  • deeper client relationships built earlier in a lawyer's career;
  • business development practiced by associates, not just by partners;
  • narrower but deeper expertise delivered with stronger communication skills; and
  • financial literacy and technology adaptability as baseline expectations.

The midsize firms that are getting ahead are not waiting for a full strategic transformation before they start. They began with one workflow type and made decisions about what the redeploy time would look like. They were not the fastest movers, they were just the most deliberate.

Three questions worth answering now

Before your firm makes its next AI implementation decision, answer three questions in writing. Not because the answers must be shared, but because writing them down quickly reveals whether they have genuinely been resolved 鈥 or merely assumed.

1. Does this work lend itself to AI, and where does it genuinely save time or add value?

Not all work is equal, and the clearest early wins come from work that is document-heavy, research-intensive, or templated, in which AI can reduce time without increasing the verification burden. Identifying that work specifically, rather than assuming AI improves everything, is where to start.

2. Where does AI save time on our key services, and where does it enable a genuinely better or new output?

For work in which AI primarily saves time, the commercial answer depends on pricing model and capacity. For fixed-fee work, efficiency gains go to margin. For hourly work, the question is whether freed-up time goes on more matters, higher-value work that justifies higher rates, or new service offerings. For work in which AI enables a genuinely better or new output, the question is what that enhanced or new service justifies charging, which may be different from what the same work commanded before. Neither question is theoretical, and both need a specific answer for each work type.

3. What are we doing to make the value of our AI investment visible to the clients who are funding it?

This means being able to say, specifically, what has changed in terms of faster turnaround, earlier risk identification, and more proactive advice. Do not simply assert that AI is being used responsibly.

Today, midsize firms that can answer these questions clearly for clients are not just better positioned to capture value from AI, they are building the competitive foundations that the legal market will reward over the next decade and beyond.

This article draws on TRI鈥檚 Managing Partner Research 2026; TR鈥檚 Future of Professionals 2026; TRI鈥檚 Law Student Pulse Survey 2026; TRI鈥檚 AI in Professional Services 2026; and TRI鈥檚 2026 State of the UK Legal Market.

In the next installment of this series, we will explore how to identify your midsize firm's best entry point for AI adoption, which practice areas and work types make the clearest commercial case, and how to build from there.

Follow us on social

Have questions?

Get in touch with one of our solutions experts....
成人VR视频 Institute logo

Featured Event

Table of
Contents
H2
H3
H4
H5
H6
September 8, 2026
The capacity question: What midsize law firms need to decide before they adopt AI
Midsize law firms will only realize meaningful value from AI if they first decide how to strategically redeploy the lawyer capacity that AI creates, while simultaneously addressing the talent, client, and ROI challenges it creates.
12 min
September 8, 2026
Legal AI & Technology
The capacity question: What midsize law firms need to decide before they adopt AI
Michelle Nesbitt-Burrell
Marketing Strategy Director
成人VR视频
Headshot of Michelle Nesbitt-Burrell
AI literacy
Legal Innovation
Midsize law firms
Generative AI
Agentic AI
Law firm culture
Technology training
Tech adoption
Legal professionals
How AI is hollowing out the legal profession's judgment pipeline 鈥 and how to fix it
The 4 scenarios: Which law firm business model are you building?
The AI adoption board game: Why law firm leaders can't afford to play it safe