/* vantage · public/css/base.css · Fix 1 · v84
   v84 (37.3 — Pete, 2026-10-24: "I want to be able to reorder the tasks, so certain tasks can go before or after other tasks"):
   ↑ and ↓ on each task's line under the PDF (task.js v78), a gap where there is nowhere to move, so the switches line up.
   v83 (37.2 — Pete, 2026-10-24: "When we are viewing a page that doesn't need map or PDF we don't need to have the toggle on
   the thin header, and we can have the solway dropdown say Solway - 366374"): the header's Map | PDF switch away on a page
   with no map or PDF (drawers.js v23 — `hidden`, the header data-noview); there the job site's rectangle carries its name
   on a phone too, unless the sliver has no room for it (data-noname — then the name heads the list, as before).
   v82 (36.28 — Pete: "get rid of their names at the top for the LBD main PDF … Never put people's names into the program,
   only on data entry PDFs"): .lbdsheet__ask and its parts are gone — whose work a row is, is the sheet's INITIALS column.
   v81 (36.27 — Pete, on his phone: "I tried to put a date in and hit enter and nothing happened"): .lbdsheet__ask — whose
   sheet it is, held at the top of the PDF's box over the enclosure sheet (the names, the one picked ringed, and under them
   what the last day typed did, two lines' room always so the sheet never moves); a day waiting for a name is dashed.
   v80 (36.23): .sheetview__again — Try again under the words of a sheet or book page that would not open (sheetview.js v8).
   v79 (36.19 — Pete, 2026-10-22: "When the drawers drop back everything should be a square, just keep the info area and I in
   a circle … for the dialogue and command box stack two squares on top of each other so it's a rectangle" · "You don't need
   to add the theme box that can be there only when the drawers open" · "after /sync 'syncing...' that blinks"): FOLDED, A
   DRAWER IS SQUARES — the ☰, Vantage, Egan, the person, the ⓘ at the left foot; command over dialogue, one rectangle; the
   lights one over the other at the right foot; no theme on a folded drawer (.drawer__rail*). .dialogue__dots — a working
   line's dots in a box of their own width.
   v78 (36.15): .reassign — Inverter Reassignments, the official list of the 16 (reassign.js): a table that scrolls sideways in
   its own box on a phone.
   v77 (36.14 — Pete: "that crew … should just stay centered"): .chiprow--center — half the line's width of room at each end of
   the crews' line, so any crew can stand in its middle (chiprow.js v3).
   v76 (36.13 — Pete, 2026-10-22: "select a crew then select tasks — a crew should always have tasks"): .atlas__tasks — the crew's
   own tasks, ONE line under the map (Layout 2), the picked one in its middle; .taskchip is a task's chip in its crew's colours,
   as a crew's chip is (light until picked, its colour when picked, a ring — never a heavier face).
   v75 (36.12 — Pete, 2026-10-22: "could you put a sync button next to the refresh button just for me"): .header__owngroup —
   Pete's own Sync (⇅) and Refresh (↻), one group a hair apart, before the light; .header__own is either; Sync wears the
   light amber while a sync runs ([data-running]); on a phone's sliver each is its glyph's own width, and each steps aside
   where there is no room ([data-noroom]) — the group takes none when neither stands ([data-empty]).
   v74 (36.11 — Pete, 2026-10-22: "I really want this to be consistent in both map and PDF … In the main window I want on
   the first line: the wiring button the racking button and the zoom buttons. On the second line … all of the location
   dropped Downs including the up button which always be there just below the zoom buttons … On the third line I want the
   crew selection … All of the tasks should be below the map or the PDF"): THE THREE LINES (.atlas__up.nav3, .navline,
   .navline__l / __r / __slide) — the map's and the PDF's alike, every control on them one height (--nav-h); the zoom
   (.zoomdock, zoomdock.js) at the first line's right end; the crews on every face (the List too); an open section's and
   LBD's or PCS's own header off (the description box has its words), and their tasks UNDER the rows or the page at every
   width; a book page's line off, a sheet's lines under it; the left drawer's View / Edit (.entry__viewtools).
   v73 (36.10 — Pete, 2026-10-22: "For all of the wiring maps where it shows the rows, let's go by load break instead of
   subsection"): the Wiring map's rows are an LBD's — section.js v8 puts each circuit's band over its rows (.tube__circ,
   ordered first in the row's column, the bands of one circuit joined across the gaps, two tones taking turns; the first
   row's carries its name and takes a tap for all its rows; .is-marked the circuit tapped on the map, .is-picked when all
   its rows are); the pier letters start the band's height lower to stay level with the rows.
   v72 (36.7 — Pete, 2026-10-22: "i want a refresh button at the top thin header, just for me"): .header__refresh — ↻ beside
   the light, the ☰'s size on a desk and the glyph's own width on a phone, never taller than the header; [data-noroom] where a
   phone's sliver has no room for it after the job site's logo (drawers.js v18 draws it for Pete's account only).
   v71 (36.6 — Pete, 2026-10-22: "vantage: the racking and wiring buttons should never move and they should be on the left
   side, the draw/list toggle should come after those buttons and the nav drop downs"): LAYOUT 2's bar over the map
   (.atlas__lead--drawers, site.js v42) is Racking · Wiring FIRST, at its left edge, then Up, the dropdowns, the zoom, and
   the Draw | List switch LAST, at its right end — one line on a desk; on a phone Racking · Wiring with Up or the zoom the
   first line, the dropdowns and the switch the second (the narrowest: the switch a third line, at its right, never shorter
   than a dropdown). Racking · Wiring, Up and the zoom are one height on a phone's first line, so Racking · Wiring are the
   same size and place on Racking and Wiring in every state. Layout 1's bar is as it was (the switch first).
   v70 (36.5 — Pete, 2026-10-22: "vantage on the pc: the solway drop down should have 'Solway Solar - 366374' (this should
   be at the top of the drop down on mobile)"): the job site's rectangle on a wide header holds its name between the logo
   and the arrow (.doorway__name, the label size, bold, one line — the header never grown); where the name is not shown —
   a phone, a header 44rem or narrower (where its words always went), Layout 1's banner — it is the first line of the list
   (.doorway__title, bold, a rule under it). ON A PHONE THE LIST IS SEEN: it dropped from the sliver, which clips what runs
   out of it (overflow: hidden), so it opened unseen — while it is open the sliver lets it out and stands over the page,
   and the list is the sliver's width under it (never off a 320 phone's edge). The header's list is as tall as the screen
   leaves it, so every entry is seen at once (the old 14 lines cut Blank Cells On The Sheets off on a desk).
   v69 (36.4 — Pete, 2026-10-22: "the scroll bars go over the rounded corners, please shore up so that they stay under the
   rounded corners"): every rounded box's scrollbar track stops where its corner's curve ends — the track's margin is the
   box's own --radius (the cap for .viewer__box and .tasksheets__grid; the polygon's own corner for the drawer's dialogue
   box, top for the input, foot for the response). On a mouse-and-screen device the .scrolls boxes are drawn by their
   ::-webkit-scrollbar rules (the same quiet look — Chrome ignores those while scrollbar-width/-color are set), and a
   rounded box that had the browser's plain bar gets .viewer__box's bar; a phone keeps its overlay bar. `npm run check:corners`.
   v68 (36.0 — Pete, 2026-10-22: "i need a page, just for me, to add to do items, so i can check them off as i go"): MY TO-DO
   (.todo, todo.js) — the box and Add on one line at the top; one line under it, one height whatever it says, for what was
   last done and Undo; each item a card a row tall (3rem — the skeleton the same), the box and the words ONE tap target, a
   checked one struck through with its box filled in the button's colour; Take off small and quiet at the row's end; Done
   folded under its own heading. A rem measure, never a pixel; tokens only.
   v67 (35.15 — Pete, 2026-10-22: "the drawers should not be open at the login screen"): .frame2[data-signedout] — the sign-in
   page — has no drawers, no grips, no ☰, and nothing on the header but the mark (drawers.js v16); the one-tap line
   (.login__tap) is two lines high whatever it says, so nothing under it moves as Google answers.
   v66 (35.11 — Pete, 2026-10-21: "Let's put the up to button next to racking and wiring buttons on the map"): UP in the bar,
   right after Racking · Wiring (.atlas__upat, site.js v40) — the open place's own Up (a section's, a subsection's, an open
   LBD's or PCS's, a sheet's) not shown in its header ([data-upbar]). A desk: one line, "Up to Block 10". A phone: "↑ Block
   10" on the first line beside Racking · Wiring (on Racking, after the switch, where the map's page is 22.5rem or more —
   a 412-wide phone; narrower, it leads the second line, before the dropdowns; the narrowest, a line of its own over them).
   On a phone, on Wiring, Racking · Wiring and Up are no taller than the dropdowns, and an open LBD's or PCS's name and Drawing share one
   line (the line its Up gave up) — so the open LBD keeps the room it had for its page and Completed (check:lbds part 7).
   v65 (35.8 — Pete, 2026-10-21: "the egan button should go all the way left and right. the racking and wiring buttons should
   be before the block and section dropdowns. the print/export toggle and buttons should be directly under the Egan dropdown
   … lets call it the print/export dropdown. the description box should be at the bottom of the left hamburger at all
   times, if things need to scroll, the will scroll behind the description box … it should look similar to the status
   area in the right hamburger. the edit button should go under the View Edit Drop down"): THE BAR'S LEAD is the switch,
   Racking · Wiring (.atlas__viewsat), Block · Section, then the zoom (.atlas__ctl) — one line on a desk; under 38rem the
   views and the zoom on the first line and the switch and the dropdowns on the second (a break between them that is
   the gap itself), under 21.5rem the dropdowns a third line, half each. THE LEFT DRAWER: Egan's rectangle the drawer's
   width (its logo left, its arrow right); .ddrop — Print / Export and View / Edit — the same rectangle, its words left, the
   arrow right, what it holds in place under it; .drawer__about — the description box — at the drawer's foot always
   (sticky), the panel's ground behind it so what scrolls goes under it, in the status area's look.
   v64 (35.7 — Pete, 2026-10-21: "Let's move edit map to the left hamburger and move racking and wiring to where edit map was
   and keep it all on the same row so condense the zoom buttons a little if you have to. On the right hamburger get rid of
   inbox and text crew buttons and combine the input box and the readout box in the same polygon but make the input box a
   slightly more white or clear color than the readout box"): the bar over the map — − · + · Fit (.map__zoom, a glyph each,
   square) and Racking · Wiring (.atlas__views) on the controls' line; Edit map at the top of the left drawer's entry header
   (.entry__mapedit, the whole width, empty and taking no room for anyone who may not); the right drawer's dialogue box ONE
   polygon — the input on top in --dialogue-input-fill (a little whiter, clearer), the response under it in the fill, one
   line between them, no gap, no box in a box.
   v63 (35.6 — Pete, 2026-10-21, the Racking Form Tracker on his phone: "I need to be able to see that button when I scroll
   down I cannot scroll down to the button. Also the headers and the black background should be condensed, is way too much
   waste of space up there"): THE FORM TRACKER, CONDENSED — the title, Racking | Wiring and the two pickers ONE line (the
   title left off under 40rem, where the ringed Racking | Wiring says which page it is; the line slides sideways when it
   does not fit), small; the black header only as tall as its crews' names (it was the tab's 156 px), the blank row under
   it a sliver; and the tab's box ends where the page's panel ends (--ft-h measured — formtracker.js v5), so Also In under
   the tab is reached by scrolling the box itself.
   v62 (35.2 — Pete, 2026-10-21: "And make a separate page for the wiring"): the form tracker's width is its own columns'
   (--ft-ncols — ten on Racking, two on Wiring), and Racking | Wiring at its top (.ft__faces) wears the ring on the page shown.
   v61 (35.0 — Pete, 2026-10-21: "I want a page that's similar to the tab in the V3 Solway install sheet spreadsheet … show
   all of these Crew sheets that I uploaded in the same manner as that tab"): THE FORM TRACKER (.ft — formtracker.js): the
   tab on its own white paper in either mode — its section column and square cells at the tab's own widths, its black
   header in the crews' own inks, no gridlines, the header and the section column stuck while the box scrolls, each cell a
   button holding the form's picture (a ring when picked, a count when there is more than one page, a blank page while the
   thumbnail is not made), the foot's total; the picked form large beside it on a wide page and in its place on a narrow
   one (Up to the Form Tracker), its own line of Zoom N% and Fit, the pages scrolling in a box of the tab's height.
   v60 (34.22 — Pete, 2026-10-20: "Each individual should take up one or two lines"): Crew Sign-In's people are two lines
   each — who and how they stand with the tier on the first, the password box and the small buttons sliding sideways on the
   second; the card's padding is the small one.
   v59 (34.21 — Pete, 2026-10-20: "can you make everybody a sign in based off of the employee personal info"): Crew Sign-In's
   Everyone On The Roster — its list of names in a box of its own height that scrolls (never the page grown by sixty
   lines), and the paste box as tall as it is dragged.
   v58 (34.19 — Pete, 2026-10-19: "when i select a subsection (wiring) i want a similar interface as the the rows for racking,
   but the rows will be split into strings … and there should be a slew drive selection for IPC, split loom, etc."): a
   subsection of the Wiring map open in the map's place (.atlas[data-subsection], as [data-open] is a racking section) —
   section.js v7's rows as their STRINGS (.tube__string, each named .tube__strname S1 …, a firmer line between them) and
   each row's SLEW DRIVE a spot of its own (.tube__slew--wire — larger than racking's SD, ringed in the task's colour when
   a slew drive task is picked, wearing its day when done; the strings stand back then, .tube--atslew); the enclosure's
   button beside Up (.sec__enc).
   v57 (34.18 — Pete, 2026-10-19: "for all of the dropdown for the 'logo's i want the logo to be the 'name' of the dropdown (so a
   rectangle with the logo inside and next to the logo, the dropdown arrow). i want it to be obvious that the logo is a
   dropdown so maybe make the arrow a little bigger"): .doorway--logo — Egan, the job site, Vantage — is a rounded rectangle
   (the one shape) holding the logo and, beside it, .doorway__caret at --door-caret (a quarter past the card heading's size, bigger than the
   label-sized arrow the words' face had); the whole rectangle is the button. Sized into the header and the drawers' top
   line, never growing them; folded to the rail the arrow goes. #onhold's groups (.onhold).
   v56 (34.18 — the Wiring map's LBD areas and rows, map.js v16): .shape--area and .shape--row are clear like a section's
   (the canvas draws them); a row is over its subsection, so a tap on it is the row's.
   v55 (34.16 — the Wiring map's subsections, map.js v15): a subsection's element (.shape--sub — what a tap is found on; the
   canvas draws it) is clear like a section's, its name a quarter of the way down it.
   v54 (34.15 — Pete: "in light mode you have dark text on a dark background polygon"): the LBDs' and the PCS' tags on the
   map wear --crew-a-ink — the ink measured to read on a crew's light tier in each mode (dark words in dark mode, light in light mode).
   v53 (34.11 — Pete, 2026-10-19: "Racking and wiring should be on the same line"): the four views in the left drawer are
   two lines of two — Racking · Wiring, then Remediation · Housekeeping — each half the drawer, the long two breaking at
   their soft hyphen where the drawer is narrow.
   v52 (34.9 — Pete, 2026-10-19: "Put the remediation and housekeeping buttons next to each other"): in the left drawer the
   four views are a grid of two — Racking and Wiring a line each, Remediation and Housekeeping side by side, each half;
   where the drawer is too narrow for a whole word the two break at their soft hyphens (task.js v57), never cut, and the
   two stay one height.
   v51 (34.8 — Pete, 2026-10-19: "I want all of the tasks where you can select what's viewed on the PDF should be listed.
   it should not be the scroll left and right, I want them listed top to bottom"): the tasks under the PDF are a LIST —
   .viewer__taskhead (Tasks on the form · N of M, All) over .viewer__tasklist, each task a line of its own; on a wide view
   the list runs down in columns side by side (.viewer__taskcols, CSS columns — the order goes down each column), so all of
   them are on the screen at once; longer than its room (a phone), it scrolls up and down in its own box, never sideways.
   v50 (34.7): the row map's SER# box is always there — no stacked note, no hidden box.
   v49 (34.6): the row map's SER# place (.sec__field--ser) — the box for a task the tracker keeps a SER# for, a line saying
   why not for any other, in ONE cell, so the entry is one height whichever is up; a row being painted takes no text
   selection or callout.
   v48 (34.5 — Pete, 2026-10-19: the PDF view's lines): .viewer__row — each line over and under the PDF (Digital | Hand Scan
   with Zoom N% and Fit; Block · Section; the crews; the tasks under the pages) is ONE line that slides sideways, as the
   crews' line does (.chiprow); its parts never shrink or wrap. .viewer__box takes no page zoom from two fingers
   (touch-action pan-x pan-y) — the pinch zooms the pages inside it (task.js v55).
   v47 (34.3 — Pete, 2026-10-18, on his phone, a section open: "The buttons overlap here"): the bar over the map and the crews' line never give up their height (flex-shrink 0) — where the map's page is narrow (a phone, or a phone's larger text) Block · Section take a second line, and an open section's own height squeezed the bar back to one, so the crews lay over the dropdowns. And .crewlock — the screen a crew sign-in's phone shows outside every place a crew may use Vantage.
   v46 (34.1): Crew Sign-In — a box inside a field's label no longer takes the row's sideways share as its height (This Phone's name box stood 12rem tall).
   v45 (34.0 — crew sign-in): .login__crew — the username box on an approved phone, its line four lines high whatever it says; .crewsign — Crew Sign-In (#crew-signin) and Your Password (#password).
   v44 (chiprow.js): the crews over the map and over the PDF are ONE LINE that scrolls sideways (.chiprow in .atlas__crews / .entry__crews) — one height whatever the view holds, so the map never moves when the crews come or the view changes; a fade on an end with more past it.
   v43 (task.js v54): .entry__picks — the view's crews and the crew's tasks over the PDF, in the main window; .viewer__empty — a view with nothing assigned yet.
   v42 (drawers.js v10 — Pete, 2026-10-18: "the Solway solar … moved over to the main header … on mobile. Just use the logo" · "For housekeeping there should be a message on the map that says nothing assigned yet"): the job site's doorway on the phone's header is its logo alone, and the typed name gives way to it; .map__note — a view with nothing on the map says so, in the middle of the map, never taking a tap.
   v41: the PDF's bar holds no buttons now (Missing sheets and Blank cells off it — task.js v52).
   v40 (Pete, 2026-10-17: "The Data Entry PDFs and the Maps ARE THE BACKBONE OF THE SITE! NEVER CHANGE WITHOUT MY PERMISSION"): v38's crews % table (.crewpct) is taken out — All Racking's PDF is its data entry form again.
   v39 (Pete, 2026-10-17: "the columns selected are what's used to create the tasks … it should look identical to the spreadsheet in the PDF view"): MAKE TASKS FROM COLUMNS on the sheet viewer (.gsheet__make — the picks, the rows, the crew, what will be made; a ring on a picked role) and THE SHEET AS A CREW'S PDF (.sheetform — the tab in its box, its task cells inputs with the sheet's own look, Vantage's entries marked .is-vantage).
   v37 (Pete, 2026-10-17: "the Solway drop down and logo can move to the thin header … the create and view can go up on the main header as well"): on a wide screen THE HEADER holds the job site's doorway (its logo and dropdown, where the typed name was), Map | PDF and the tools (.header__tools — Task ▾ · Crew ▾ · Location ▾ · Island ▾ · DigiTools), their lists dropping under the header over the page (the header is not clipped there, and stands over the page); as the header narrows the tools' words go, then the job site's (a container query, hdr). A phone's sliver is as it was.
   v36 (Pete, 2026-10-17: "just look at the blank cells"): A SHEET'S BLANK CELLS — marked in red over the scan (.scan__marks, turned as the check turned the sheet; hidden by Hide blank cells, kept on the device: :root[data-scan-marks-off]), said under it (.scan__blank); BLANK CELLS ON THE SHEETS (.blankcells — the faces of #tasksheets, the kinds as chips that wear a ring when picked, block by block with its header stuck, a sheet's marked picture opened in place).
   v35: Crew Leader Task Sheets has eight sheet columns (QAQC - Swage & Torque).
   v34 (Pete, 2026-10-17: "in the 'PDF View' of Vantage, i want to be able to see the corresponding scan of handwritten sheets … a toggle to switch between 'Hand & Scan' and 'Digital' … Also, I want to know what sheets we are missing"): THE PDF'S OWN BAR (.viewer__face — Hand & Scan | Digital, Missing sheets, what the face shows, one height whatever it says); A SHEET, SCANNED (.scan — upright, as wide as the box at its own shape before the picture comes, its name and Open · Original scan under it; .scan__none a sheet not in yet, .scan__part rows no scan carries); CREW LEADER TASK SHEETS (.tasksheets — every section × every sheet, In · Part · Missing, its first column and head stuck while it scrolls).
   v33 (Pete, 2026-10-17: "I want all documents like a file system … filtered or sorted in any possible way"): THE JOB'S FILES (.fs — documents.js v13, fs.js): its tools (find, Group by, Sort by, the order, Changed, Block, Who; the kinds and where-from as one line each that scrolls sideways; what is shown and Clear the filters), the bar for the chosen one (.fs__act — two lines, one height chosen or not), the work place (.fs__work — earlier revisions, or the pages of a document being made into another: .pagepick), and the list in a box of one height that scrolls (.fs__list): its columns' names stay put, the rows are drawn only where they can be seen, each one height (--fs-row), indented by their folder's depth; on a narrow list each row is two lines.
   v32 (Pete, 2026-10-17: "Let's just add a viewer, and if somebody wants to edit there's an edit button that opens it in Google Sheets"): A GOOGLE SHEET, SEEN (.gsheet — gsheet.js): its head of one height (Back · Edit, the sheet's name to the letter, the tabs on one line that scrolls sideways, what is showing), and the tab itself in a box of one height that scrolls both ways — on the sheet's own paper in either mode, the column letters and row numbers, its frozen rows and columns stuck, its own looks (inline rules, OKLCH, Roboto). A Sheet's line in a folder has View and Edit (.gfolder__acts).
   v28 (Pete, 2026-10-15: "I want the exact same PDF pages used for the map, not your rendering"): the open LBD or inverter stands on the book's own page (.sheetview--book — never filtered, its own white paper), in a place of one height (.lbd__grid) whether the page, the line saying where it comes from or the stand-in drawing is in it.
   v27 (Pete, 2026-10-15, Egan's DC Underground book: "Here is the underground, the inverter layout and the LBD layout" · "I want the drawings as the maps"): an open LBD is the book's LBD layout and an open inverter the book's inverter layout (.lbddraw v2), in the book's own colours (--ug-*).
   v26 (Pete, 2026-10-15: "I want the PDF for the low brake disconnects and the PDF for the inverters to look exactly like the tab from version 3. And the map version should be a drawing of the low break disconnect"): an open LBD or inverter is a drawing (.lbddraw — the enclosure as E-505 draws it, the skid as E-541 does) where the grid of cells was; the PDF view of a block's LBDs or Inverter is the tracker's own tab (.termstab, form.css).
   v25 (Pete, 2026-10-15: "I don't see the LBDs on the map" · the LBD Terms and INV Terms tabs): an LBD or an inverter, tapped on the map, opens in the map's place as a section does (.lbd — lbdview.js): its switches or inputs as columns, a cell for each of the tab's four tasks in the crew's colour, the entry beside them; it has the quiet sheets a tapped section has.
   v24 (Pete, 2026-10-15, the electrical set): a block's LBDs and Inverter carry their wiring under the sheet's header — the enclosures and switches, or the inverters and inputs, one line that scrolls sideways (.sheetview__strip), and what was tapped on a fixed-height line (.sheetview__about).
   v23 (Pete, 2026-10-15, the engineer's sheets): a block's Inverter, LBDs or Motor-Slew stands on its own sheet in the map's place (.sheetview — its header of two lines, the sheet's box, the sheet in the mode's colours); Upload sheets lists what each page is (.sheetrow).
   v22 (Pete, 2026-10-15: an undo for "for all"): a press for many differences at once is marked while it waits for its second tap (.btn.is-armed); the choices to take back are rows (.diffs__batch).
   v21 (Pete, 2026-10-15: "Yes pull all sheets and files from autodesk"): a file or sheet from Autodesk keeps its own name and folder to the letter (.addoc, .addoc__folder); the pull's panel has its light in its title (.ad-pull).
   v20 (Pete, 2026-10-14: "crews and tasks should always have their colors assigned… Whenever a task or crew button is on the site it should be the color of the crew!" — and "when scrolling through the hamburgers the top line should always stay fixed"): a crew's or a task's button wears the crew's colour (.crewbtn — --crew-face / --crew-ink, set by colours.js wear()), a task's switch its crew's colour (.crew-sw), a task ticked on Night Vision its mark (.crewmark), a crew's card its name on the colour (.crewhead); each drawer's top line stays put while the drawer scrolls under it (.drawer__top sticky).
   v19 (Pete, 2026-10-14, on his phone: "I can't go up to the main map, the block and section selection is on there 2 times"): an open section's header begins with Up to its block (.sec__up) — its own Block dropdown and section chips are gone.
   v18 (Pete, 2026-10-14: "the Block dropdown and the section drop-down available all the time in both Map and PDF views"): the bar's lead over the map is the Draw | List switch then Block · Section (.atlas__where, .atlas__pick) — one line at any width, the dropdowns giving way before anything wraps; on the PDF each block's header IS its Block · Section (.block__pick); a block's area on the PDF (.area__note).
   v17 (Pete, 2026-10-14: "I want a theme drop-down (light, dark, neon, Xmas, etc) to the left of the hamburger on the right"): the THEME dropdown on the right drawer's top line, left of its ☰ (.theme — theme.js): its face is the design's swatch, the theme in words and ▾; its list an expansion under the line at the drawer's whole width, Mode then Design, every choice in its own colours (--theme-face, --theme-ink, --theme-band); folded to the rail, the swatch alone under the ☰.
   v16 (Pete, 2026-10-13, at the PC: "solway solar should be on the thin header above the viewport · the vantage logo should be to the right of the hamburger · the side drawers need to be able to be adjustable width"): the job site's name on the header (.header__site); the Vantage lockup and the build on the left drawer's top line beside its ☰ (.drawer__top, .drawer__build) — on a wide screen the header no longer carries the mark; each drawer as wide as it is dragged (--dw on the drawer, capped at --drawer-max) by a grip in the gap on its inner edge (.drawer__grip).
   v15: DRAW | LIST (Pete, 2026-10-13: "For the blocks - crew percent section I want that to be a separate view… a toggle, only when you're in map view, that switches between draw and list") — the map view's two faces (.atlas[data-face]): the map with its crews, or the Blocks · Crew % table alone; the switch first in the bar over the map (.atlas__face), one place in every state. The table is no longer beside the map on a wide screen, and the "Blocks %" chip and its container queries are gone.
   v14: V3'S PROGRESS MAP AND SECTION VIEW (Pete, 2026-10-11: "I need the map to be very similar to the Solway V3 progress site… when you click on a selection I want it to look the same way that I had it in version 3") — the crews over the map as chips in their own colours (.atlas__crews, .crewchip); a section's own % under its name (.shape__sub — map.js draws it by the same numbers); a tapped section in the map's place (.sec: its rows as torque tubes — .tube — the tasks as chips, the progress bars); the Blocks · Crew % table (.blocktable). The grid of boxes under the map (.mapsheet) is gone. Every colour is a token (tokens.json progress); every measure is rem.
   v13: the touch plate is also up whenever fingers are in use on the map (.map--fingers, map.js v10) — on a device whose first pointer is a mouse too.
   v12: THE MAP IS DRAWN (Pete, 2026-10-11: "it should be vector… zero blurriness… zero lag") — what is seen of a map is three canvases drawn every frame (map.js v9); the places stay as elements under them, not seen; the look of a name, a frame and a corner is still set here and read off samples.
   v11: THE MAP'S TOUCH PLATE and ONE ZOOM (Pete, 2026-10-11: "whatever my fingers are on top of when I'm zooming should not affect how the zoom works") — on a phone one clear sheet over the map takes every finger; while a map is up the browser's own page zoom is off.
   v10: SHARED WITH VANTAGE (Pete, 2026-10-11): the Document Control Center's share-with address (shown whole, selected on a tap), the Drive selector's own scrolling box, and a Drive file's card with its light.
       And a grid's unit is never wider than the box it is in — on a screen narrower than one unit (a small phone, 18rem cards) the page used to scroll sideways.
   v9: the map's stage is its own layer all the time, and the map shows the hand that drags it at any zoom (map.js v7 — one finger moves the map always).
   v8: THE MAP ZOOMS (Pete, 2026-10-11): the stage is the plan at the size it is shown, placed by map.js; the ink is one canvas; a place's corner and box show only while Edit map is on;
       the bar over the map carries Zoom out · Zoom in · Fit · Edit map. With Build 21.0's, never numbered here: one light and the lights listed, the panel is the card, a phone's drawer at two thirds, the names sized by the map.
   v7: THE HEADER (Pete, 2026-10-10): the top bar holds only the small mark and build, the Map | PDF switch and the lights (words beside them only when one is amber or red);
       the dialogue box, the readouts, Back, Rows and Admin/Worker live in the drawers; a phone's header is a sliver; preset buttons wear their own colours.
   v6: LAYOUT 2 — the drawers (Pete, 2026-10-10): the CCleaner-style frame at the foot of this file; the Rows control's hide of the dialogue box finds it in either layout.
   v5: the entry's header is pinned under the strip (headers never scroll); Print | Export's format pick; the actions group in the bar.
   v3: the status light is lit in both modes; the tools row's create-or-view pairs; one block header in the viewer; the crews row.
   v2: buttons cast their own colour on the ground (--glow-size, --glow-alpha) — the neon dark mode.
   The design system as code. Every rule here references a token from css/tokens.css.
   If you find a literal colour, radius, width, font size or gap below, it is a bug —
   the only way to add a value to the site is to add it to tokens/tokens.json.

   Layout units: % of parent, rem, vw/vh. NEVER pixels. (Addendum H §2)
   Motion: none. There is not a single transition in this file. (Addendum H §7a) */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Scrollbars: ALWAYS present on the boxes that can scroll, so one never pops into being
   when a line wraps (Pete, 2026-09-18) — and quiet: thin, no track, a faint thumb. */
.scrolls {
  overflow-y: scroll;
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb-page) transparent;
  scrollbar-gutter: stable;
}
.scrolls::-webkit-scrollbar { width: 0.5em; height: 0.5em; }
.scrolls::-webkit-scrollbar-track { background: transparent; }
.scrolls::-webkit-scrollbar-thumb { background: var(--scroll-thumb-page); border-radius: 1em; }

.dialogue__say, .dialogue__input { scrollbar-color: var(--scroll-thumb) transparent; }
.dialogue__say::-webkit-scrollbar-thumb, .dialogue__input::-webkit-scrollbar-thumb { background: var(--scroll-thumb); }

/* (v69) SCROLLBARS STAY UNDER THE ROUNDED CORNERS (Pete, 2026-10-22: "the scroll bars go over the rounded corners, please
   shore up so that they stay under the rounded corners"). A scrollbar ran its box's whole height, so its ends — and the
   browser's ▲ ▼ — sat in the curve of a rounded corner. Now every rounded box's track STOPS WHERE ITS CORNER'S CURVE ENDS:
   the track's margin is the box's own --radius, the very value its border-radius is drawn with, so the two always agree
   (a shape measured again, the Roundness slider, a drawer dragged wider).
   Chrome draws ::-webkit-scrollbar (the only bar that can be inset) only where scrollbar-width and scrollbar-color are
   left at auto — so on a mouse-and-screen device the .scrolls boxes give those two up and are drawn by the rules above,
   the same quiet look (thin, no track, a faint thumb); a rounded box that had the browser's own plain bar is given the
   bar you can SEE (.viewer__box's). A phone keeps its own overlay bar, which takes no room — a drawn bar would take
   0.5em from every drawer and the page there. Firefox has no way to inset a bar and keeps its thin one. */
@media (hover: hover) and (pointer: fine) {
  @supports selector(::-webkit-scrollbar) {
    .scrolls { scrollbar-width: auto; scrollbar-color: auto; }
    [data-shape]:not(.scrolls)::-webkit-scrollbar { width: 1em; height: 1em; }
    [data-shape]:not(.scrolls)::-webkit-scrollbar-track { background: var(--card); border-radius: 1em; }
    [data-shape]:not(.scrolls)::-webkit-scrollbar-thumb { background: var(--text2); border-radius: 1em; border: 0.15em solid var(--card); }
    [data-shape]:not(.scrolls)::-webkit-scrollbar-corner { background: transparent; }
  }
}
/* the inset itself — wherever a drawn bar is (a phone's .viewer__box too): the shapes (the same list as the shape rule) */
[data-shape]::-webkit-scrollbar-track:vertical,
.row::-webkit-scrollbar-track:vertical, .panel::-webkit-scrollbar-track:vertical, .card::-webkit-scrollbar-track:vertical,
.btn::-webkit-scrollbar-track:vertical, .dialogue__say::-webkit-scrollbar-track:vertical,
.dialogue__input::-webkit-scrollbar-track:vertical, .skeleton::-webkit-scrollbar-track:vertical,
.chip::-webkit-scrollbar-track:vertical { margin-top: var(--radius, var(--radius-cap)); margin-bottom: var(--radius, var(--radius-cap)); }
[data-shape]::-webkit-scrollbar-track:horizontal,
.row::-webkit-scrollbar-track:horizontal, .panel::-webkit-scrollbar-track:horizontal, .card::-webkit-scrollbar-track:horizontal,
.btn::-webkit-scrollbar-track:horizontal, .dialogue__say::-webkit-scrollbar-track:horizontal,
.dialogue__input::-webkit-scrollbar-track:horizontal, .skeleton::-webkit-scrollbar-track:horizontal,
.chip::-webkit-scrollbar-track:horizontal { margin-left: var(--radius, var(--radius-cap)); margin-right: var(--radius, var(--radius-cap)); }
/* …the boxes rounded at the cap rather than measured */
.viewer__box::-webkit-scrollbar-track:vertical, .tasksheets__grid::-webkit-scrollbar-track:vertical { margin-top: var(--radius-cap); margin-bottom: var(--radius-cap); }
.viewer__box::-webkit-scrollbar-track:horizontal, .tasksheets__grid::-webkit-scrollbar-track:horizontal { margin-left: var(--radius-cap); margin-right: var(--radius-cap); }
/* …and the dialogue box in a drawer, one polygon: the input is its rounded TOP and the response its rounded FOOT, each with
   the polygon's own corner (read on .dialogue and carried down), square where the two meet */
.drawer .dialogue { --dialogue-corner: var(--radius, var(--radius-cap)); }
.drawer .dialogue__input::-webkit-scrollbar-track:vertical { margin-top: var(--dialogue-corner); margin-bottom: 0; }
.drawer .dialogue__say::-webkit-scrollbar-track:vertical { margin-top: 0; margin-bottom: var(--dialogue-corner); }

/* hidden means hidden, whatever display an element was given. */
[hidden] { display: none !important; }

html {
  /* The 0-100 type scale hangs off the user's root size, so a font swap or an
     accessibility bump moves the whole ladder together. */
  font-family: var(--font);
  line-height: var(--lh);
  background: var(--bg);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--t-body); /* body is step 5 of 6 */
  line-height: var(--lh);
  /* Roboto Condensed is the primary cut; nothing in this file falls back to Arial. */
}

/* ---------- type — six steps, no seventh ---------- */

.t-page { font-size: var(--t-page); }
.t-section  { font-size: var(--t-section);  }
.t-card  { font-size: var(--t-card);  }
.t-label  { font-size: var(--t-label);  }
.t-body  { font-size: var(--t-body);  }
.t-small  { font-size: var(--t-small);  }

h1, h2, h3, h4, p, ul, ol, figure {
  margin: 0;
}

h1 { font-size: var(--t-page); font-weight: 700; }
h2 { font-size: var(--t-section);  font-weight: 700; }
h3 { font-size: var(--t-card);  font-weight: 700; }
h4 { font-size: var(--t-label);  font-weight: 600; }

.muted { color: var(--text2); }

/* ---------- shape — one shape only ---------- */

/* --radius is measured and set per element by js/shape.js: 9% of the SHORTEST side (was 27),
   capped. The token is the fallback for anything the observer has not reached yet, so
   nothing ever renders square and then changes shape. */
[data-shape],
.row, .panel, .card, .btn, .dialogue__say, .dialogue__input, .skeleton, .chip {
  border-radius: var(--radius, var(--radius-cap));
}

/* ---------- spacing — inside < between, ratio 2:1 ---------- */

/* One element per row, full width, stacked vertically. (Addendum G §1) */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  width: 100%;
}

/* Where a page genuinely has repeated units, extra width shows MORE AT ONCE, not
   bigger — same tap targets, more columns. (Addendum H §1.1) */
.grid {
  display: grid;
  /* a unit is never wider than the box it is in: on a screen narrower than one unit the column is the box's width,
     not the unit's — which used to push the page sideways (v10) */
  grid-template-columns: repeat(auto-fit, minmax(min(var(--unit, 12rem), 100%), 1fr));
  gap: var(--gap);
  width: 100%;
}

.pad {
  padding: var(--pad);
}

/* ---------- surfaces — the lightness ladder ---------- */

.panel {
  background: var(--panel);
  color: var(--text);
  padding: var(--pad);
  width: 100%;
}

.card {
  background: var(--card);
  color: var(--text);
  padding: var(--pad);
  width: 100%;
}

.raised {
  background: var(--raised);
  color: var(--text);
  padding: var(--pad);
}

/* Borders are for CONCRETE things — headers and structural furniture — so they feel
   built rather than floating. Cards and softer elements stay borderless on the ladder. */
.structural {
  border: var(--border);
}

/* ---------- the page frame ---------- */

/* Mobile-first. The desktop does not reflow or stretch the mobile page: the mobile
   column keeps its width on the RIGHT and context wraps around it on the left.
   (Addendum H §1.1) */
.frame {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  width: 100%;
  padding: var(--gap);
}

.frame > * {
  min-width: 0;
}

@media (min-width: 60rem) {
  .wrap {
    display: grid;
    grid-template-columns: 1fr minmax(0, 30rem);
    gap: var(--gap);
    align-items: start;
    width: 100%;
  }
  /* Tab order follows the work, not the layout: the panel is first in the DOM and
     first in tab order, the context second. Deliberate — do not "fix" it.
     (Addendum H §7f) */
  .wrap > .context { order: 1; }
  .wrap > .column  { order: 2; }
}

/* ---------- row 2 — the dialogue box ---------- */

/* TOP of the strip's working area, visible at all times, never collapses. (Addendum I §2)

   AND IT IS A FIXED SIZE. Pete, 2026-09-18: the row is split in two — the RESPONSE on the
   left, the INPUT on the right — and each side is a fixed-height box that scrolls when what
   is in it is longer than the box. Under both, one single line holds Talk, any action
   buttons a conflict needs, the phase/mode and the data status. Nothing here can change the
   height of the row, so the row has one height in every state it can ever be in. */
.dialogue {
  position: relative;   /* the bottom edge is the resize handle (.dialogue__grip) */
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: 'say entry';
  gap: var(--pad);
  width: 100%;
  padding: var(--pad);
  border: var(--border);
  color: var(--text);
}

/* Left: the response. Exactly --dialogue-say-lines tall, always; longer scrolls. Debug
   verbosity lands here too — Addendum I §6, it changes what the box shows and opens
   nothing separate. */
.dialogue__say {
  grid-area: say;
  height: var(--dialogue-say-height);
  min-height: var(--dialogue-say-height);
  overflow-y: scroll;
  overscroll-behavior: contain;
  min-width: 0;
  padding: var(--pad);
  background: var(--dialogue-fill);
  color: var(--dialogue-ink);
}

.dialogue__msg { font-size: var(--t-label); white-space: pre-wrap; }

.dialogue__log {
  font-size: var(--t-small);
  color: var(--text2);
  white-space: pre-wrap;
  margin-top: calc(var(--pad) / 2);
}

/* Right: the input, with the standing strip (Inbox · Text Crew) FIXED under it. The pair
   is exactly as tall as the response box: the input gives up the strip's height, so the
   row keeps its one height and the buttons never scroll away (Pete, 2026-09-27). */
.dialogue__entry {
  grid-area: entry;
  display: flex;
  flex-direction: column;
  gap: calc(var(--pad) / 2);
  height: var(--dialogue-say-height);
  min-height: var(--dialogue-say-height);
  min-width: 0;
}
.dialogue__entry > .dialogue__input { flex: 1 1 0; height: auto; min-height: 0; }
.dialogue__standing {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: nowrap;
  gap: calc(var(--pad) / 2);
  min-width: 0;
  overflow: hidden;
}
.dialogue__standing > .btn {
  flex: 1 1 0;              /* the two share the strip evenly; a phone's narrow column trims with … */
  min-width: 0;
  width: auto;
  font-size: var(--t-small);
  padding: var(--pad);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The input itself scrolls the same way as the response — Enter sends, Shift+Enter is a
   new line. Every entry field sits at the top of its page; this one is the top of every
   page there is. Alone (other pages reuse the class) it is the full response height. */
.dialogue__input {
  grid-area: entry;
  width: 100%;
  height: var(--dialogue-say-height);
  min-height: var(--dialogue-say-height);
  resize: none;
  overflow-y: scroll;
  font: inherit;
  font-size: var(--t-label);
  line-height: var(--lh);
  color: var(--dialogue-ink);
  background: var(--dialogue-fill);
  border: var(--border);
  padding: var(--pad);
  min-width: 0;
}

.dialogue__input::placeholder { color: var(--dialogue-ink); opacity: 0.7; }
.dialogue__log { color: var(--dialogue-ink); opacity: 0.8; }

/* The box's own bottom edge is the resize handle (dialogue.js v14, Pete 2026-09-27: no bar,
   no wasted space): an invisible strip over the bottom padding; the cursor says what it does.
   Drag it and the two boxes change height together, by lines. */
.dialogue__grip { position: absolute; left: 0; right: 0; bottom: 0; height: var(--pad); cursor: ns-resize; touch-action: none; user-select: none; z-index: 2; }

/* Action buttons — a conflict's two choices — sit under the message inside the response
   box, so they scroll with it and cannot add a line to the row. */
.dialogue__actions {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pad) / 2);
  margin-top: calc(var(--pad) / 2);
}

.dialogue__actions:empty { display: none; }

/* the session's scroll-back under the current line: scroll down inside the box to read back
   through everything said since it opened (Addendum L §2.1); the box itself never grows */
.dialogue__history { margin-top: calc(var(--pad) / 2); border-top: var(--border); padding-top: var(--pad); }
.dialogue__history:empty { display: none; }
.dialogue__past { display: flex; gap: calc(var(--pad) / 2); font-size: var(--t-small); opacity: 0.85; white-space: pre-wrap; padding: var(--pad); }
.dialogue__past--you { font-weight: 700; }
.dialogue__past--error { text-decoration: underline; text-decoration-thickness: 0.08em; }
.dialogue__when { flex: 0 0 auto; font-variant-numeric: tabular-nums; opacity: 0.8; }

/* Customized Vantage Design: three even columns across the full width, one on a phone */
.three { display: grid; grid-template-columns: 1fr; gap: var(--gap); width: 100%; min-width: 0; }
.three > * { min-width: 0; }
@media (min-width: 60rem) { .three { grid-template-columns: 1fr 1fr 1fr; align-items: start; } }
.presets { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: var(--pad); }
.presets > .btn { width: auto; }
/* a preset's button wears the preset's own colours (account.js sets --bl/--bc/--bh and --swatch): the face is its
   button colour, a band along the foot runs through its seven row hues — Christmas reads red and green, Halloween
   orange and purple (Pete, 2026-10-10) */
.presets > .preset { background-image: var(--swatch, none); background-size: 100% 0.55em; background-position: center bottom; background-repeat: no-repeat; padding-bottom: calc(var(--pad) + 0.55em); }

/* two columns side by side, no toggle (the Rules + Health Check page); one on a phone */
.two { display: grid; grid-template-columns: 1fr; gap: var(--gap); width: 100%; min-width: 0; }
.two > * { min-width: 0; }
@media (min-width: 60rem) { .two { grid-template-columns: 1fr 1fr; align-items: start; } }
.health__row h4 { display: flex; align-items: center; gap: calc(var(--pad) / 2); }
.health__fix { font-weight: 700; overflow-wrap: anywhere; }

/* the history page */
.history__row { display: grid; grid-template-columns: auto auto 1fr; gap: calc(var(--pad) / 2) var(--pad); align-items: baseline; padding: var(--pad); background: var(--raised); }
.history--owner .history__row { grid-template-columns: auto auto auto 1fr; }
.history__row--you .history__text { font-weight: 700; }
.history__row--error .history__kind, .history__row--debug .history__kind { font-weight: 700; }
.history__text { white-space: pre-wrap; min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 45rem) { .history__row, .history--owner .history__row { grid-template-columns: 1fr; } }

.dialogue__actions > .btn {
  width: auto;
  font-size: var(--t-small);
  padding: var(--pad);
  white-space: nowrap;
}

/* ---------- row 2 — status: phase, mode, data. Read-only. ---------- */

.row.status {  /* .row is declared later in this file and says wrap; this must win */
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--pad);   /* the buttons here are padded pad/2 inside, so pad between them keeps 2:1 */
  font-size: var(--t-small);
  color: var(--text2);
  white-space: nowrap;
  overflow: hidden;
}

.status > .btn { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: var(--pad); }
.status__item b { font-weight: 700; color: var(--text); }

/* The three readouts sit at the RIGHT, the buttons at the left (Pete, 2026-09-26). Each slot is
   as wide as the widest value it can hold (set in dialogue.js), so a change of phase, mode or
   data status moves nothing. (.status__first, not :first-of-type — the Rows control is a span
   too, and was the one taking the push.) */
.status__item { flex: 0 0 auto; text-align: left; overflow: hidden; text-overflow: ellipsis; }
/* every value a slot can hold, stacked in one cell; the current one shows, the others hold the
   width — so the slot is exactly its widest real value and nothing beside it ever moves.
   Used by the status readouts and the Rows buttons (Hide/Show). */
.vals { display: inline-grid; vertical-align: baseline; }
.val { grid-area: 1 / 1; visibility: hidden; white-space: nowrap; }
.val[data-on='true'] { visibility: visible; }
.status__data { overflow: visible; }   /* sized to its widest value already; the light's glow must not be clipped square */
.status__first { margin-left: auto; }
/* the signed-in person's mark, small, just before the phase */
.status__mark { display: inline-flex; align-items: center; flex: 0 0 auto; }
.status__mark .user-mark { height: 1.7em; width: 1.7em; font-size: var(--t-small); }

/* Urgent flashes the background a few times, then stops. Never a permanent pulse.
   (Addendum I §4) — the keyframes change colour only; no layout property animates,
   so the view still cannot jump. */
.dialogue--urgent {
  animation: dialogue-flash 0.4s steps(1, end) 6;
}

@keyframes dialogue-flash {
  0%, 100% { background: var(--row-dialogue); }
  50%      { background: var(--panel-selected); }
}

@media (prefers-reduced-motion: reduce) {
  .dialogue--urgent { animation: none; background: var(--panel-selected); }
}

/* ---------- controls ---------- */

.btn {
  font: inherit;
  font-size: var(--t-label);
  line-height: var(--lh);
  color: var(--button-text);
  --bl: var(--btn-l); --bc: var(--btn-c); --bh: var(--btn-h);
  --shade: 0;
  --lift: 0;
  background: oklch(calc((var(--bl) + (var(--shade) + var(--lift)) * var(--shade-dir)) * 1%) var(--bc) var(--bh));
  /* The border carries the 3:1 boundary, so the fill can stay calm near its row. */
  border: var(--border);
  /* The glow: the button's own colour, cast onto the ground around it. Drawn outside the
     box, so it moves nothing; --glow-alpha is 0 in light mode and the tube is off. */
  --glow: 0 0 var(--glow-size) oklch(calc((var(--bl) + (var(--shade) + var(--lift)) * var(--shade-dir)) * 1%) var(--bc) var(--bh) / var(--glow-alpha));
  box-shadow: var(--glow);
  padding: var(--pad);
  width: 100%;
  /* A button never pushes the page wider than the screen — the body must not scroll
     sideways at any width. Its own text is what it sizes off, never a fixed number. */
  min-width: 0;
  text-align: center;
  cursor: pointer;
}

/* Hover POPS: one rung lighter, zero movement, and nothing around it moves either. */
.btn:hover { --lift: 4; }

/* Click presses IN. */
.btn:active { --lift: -4; }

/* Selected = border + higher contrast. Brighter than anything around it so it wins in
   a grid of forty rectangles, and it persists after the mouse leaves. */
.btn[aria-pressed='true'],
.btn.is-selected {
  --lift: 6;
  border: var(--selected-border);
}

/* (v20) A CREW'S OR A TASK'S BUTTON IS THE CREW'S COLOUR (colours.js wear(): --crew-face, --crew-ink). It glows in its
   own colour; picked, it keeps its face and wears the selected ring around it, so nothing beside it moves. */
.btn.crewbtn { background: var(--crew-face); color: var(--crew-ink); box-shadow: 0 0 var(--glow-size) color-mix(in srgb, var(--crew-face) calc(var(--glow-alpha) * 100%), transparent); }
.btn.crewbtn:hover { filter: brightness(1.1); }
.btn.crewbtn:active { filter: brightness(0.9); }
.btn.crewbtn.is-selected, .btn.crewbtn[aria-pressed='true'] { outline: var(--selected-border); outline-offset: 0.15rem; }
.switch.crew-sw .switch__track { border-color: var(--crew-face); box-shadow: inset 0 0 0 0.1rem var(--crew-face); }
.switch.crew-sw.is-on .switch__track { background: var(--crew-face); }
.switch.crew-sw.is-on .switch__knob { background: var(--crew-ink); }
.crewmark { border-left: 0.3rem solid var(--crew-face); padding-left: calc(var(--pad) / 2); }
.crewhead { background: var(--crew-face); color: var(--crew-ink); padding: calc(var(--pad) / 3) var(--pad); border-radius: var(--radius-cap); }

/* Focus reuses the selected state. One visual language for "this is the thing you are
   on", whether reached by mouse, tab or touch. (Addendum H §7f) */
.btn:focus-visible,
a:focus-visible {
  outline: var(--selected-border);
  outline-offset: calc(var(--pad) / 4);
}


/* THERE IS NO DISABLED STATE. A control that is not ready keeps its normal look and a
   short line NEXT TO IT says why. (Addendum H §7) */
.not-ready {
  display: flex;
  align-items: center;
  gap: var(--gap);
  width: 100%;
}

.not-ready > .btn { width: auto; }

.not-ready__why {
  font-size: var(--t-small);
  color: var(--text2);
}

/* ---------- loading — skeletons only ---------- */

/* Grey blocks at the EXACT final size and shape, so nothing shifts when data lands.
   No shimmer: a shimmer is motion, and there is no motion. (Addendum H §7) */
.skeleton {
  background: var(--card-hover);
  width: 100%;
}

/* ---------- data — colour is who, opacity is how far ---------- */

.chip {
  display: block;
  width: 100%;
  background: var(--chip, var(--all));
  /* Fill level / opacity = percent complete. Uncoloured means nobody has. */
  opacity: var(--done, 1);
}

/* ---------- titles ---------- */

/* PROPER CASE, EVERY TITLE (Pete, 2026-09-27, a site rule): every word of a heading, a page name, a deck card or a
   dropdown entry begins with a capital — Excel's PROPER. One rule here does it for every title, present and
   future; the code writes them that way too. */
h1, h2, h3, h4, .doorway__entry, .deck__face, .deck__entry, .dropdown__face { text-transform: capitalize; }

/* ---------- footer ---------- */

.footer {
  width: 100%;
  padding: var(--pad);
  font-size: var(--t-small);
  color: var(--text2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  justify-content: space-between;
}

/* ============================================================================
   ROWS 1-4 — the permanent furniture (Addendum G §2, build step 3)
   Rows 1-5 never move, never get replaced, never change with the page.
   Everything page-specific renders from row 6 down.
   ========================================================================= */

/* The pinned strip. Addendum H §5.1: the dialogue box, the tools row and the
   filters row never scroll away; the rows above them collapse one at a time,
   least-used first — logos and nav go early. Sticky rather than fixed, so the
   page below scrolls under it and nothing is ever covered. */
.strip {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: var(--pad);
  padding: var(--pad);
  background: var(--bg);
}

/* The page reserves the strip's AT-REST height, measured once by js/pin.js and re-measured
   on resize. That is what makes collapse safe: a row that collapses makes the strip shorter
   and REVEALS the content that was underneath it, and the content itself does not move by a
   pixel. A sticky strip cannot do this — it sits in the flow, so shrinking it pulls the
   whole page up by the height of the row that went. */
#app {
  padding-top: var(--strip-height, 0px);
}

/* Collapse is instant — there is no motion on this site, and a row that slid
   away would be the view moving under the user's hand. */
.row[data-collapsed='true'] {
  display: none;
}

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--pad);
  width: 100%;
  min-width: 0;
  padding: var(--pad);
}

/* Every row its own tint, and every row's BUTTONS carry that row's hue: each row points
   the button parts at its own colour. Each button in a row is then a different shade of
   it (--shade, by position), and each state lifts it further (--lift). */
[data-row='banner'] .btn   { --bl: var(--btn-banner-l);   --bc: var(--btn-banner-c);   --bh: var(--btn-banner-h); }
[data-row='status'] .btn   { --bl: var(--btn-status-l);   --bc: var(--btn-status-c);   --bh: var(--btn-status-h); }
[data-row='nav'] .btn      { --bl: var(--btn-nav-l);      --bc: var(--btn-nav-c);      --bh: var(--btn-nav-h); }
[data-row='tools'] .btn    { --bl: var(--btn-tools-l);    --bc: var(--btn-tools-c);    --bh: var(--btn-tools-h); }
[data-row='filters'] .btn  { --bl: var(--btn-filters-l);  --bc: var(--btn-filters-c);  --bh: var(--btn-filters-h); }
/* DigiTools is a doorway, not a create — its own colour, and no shade (Pete, 2026-09-18). */
[data-row='tools'] .btn.tool--digitools { --bl: var(--btn-digitools-l); --bc: var(--btn-digitools-c); --bh: var(--btn-digitools-h); --shade: 0; }
.dialogue .btn             { --bl: var(--btn-dialogue-l); --bc: var(--btn-dialogue-c); --bh: var(--btn-dialogue-h); }

/* Shades step TOWARD the ground, so the label's contrast only ever improves along the row;
   the state lifts step away from it, and are small for the same reason. */
.strip .btn:nth-child(2) { --shade: -3; }
.strip .btn:nth-child(3) { --shade: -6; }
.strip .btn:nth-child(4) { --shade: -9; }
.strip .btn:nth-child(5) { --shade: -12; }
.strip .btn:nth-child(n + 6) { --shade: -15; }

[data-row='banner']   { background: var(--row-banner); }
[data-row='status']   { background: var(--row-status); }
[data-row='nav']      { background: var(--row-nav); }
[data-row='tools']    { background: var(--row-tools); }
[data-row='filters']  { background: var(--row-filters); }
.dialogue             { background: var(--row-dialogue); }

/* ---------- row 1 — the logo banner IS the navigation ---------- */

/* Four doorways across, Vantage larger in the centre, the view toggle at the end. Each
   doorway is a column: its logo, then a face button; open, the two swap for the list in
   the same pinned height. */
.banner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;   /* equal sides, so the centre is the page's centre */
  align-items: stretch;
  gap: var(--gap);
}

.banner__side {
  display: flex;
  align-items: stretch;
  gap: var(--gap);
  min-width: 0;
}

.banner__side--right { justify-content: flex-end; }

.doorway--big { flex: 0 0 auto; }

.doorway {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;   /* every face on the same bottom line (Pete, 2026-09-18) */
  gap: calc(var(--pad) / 2);
  flex: 1 1 0;
  min-width: 0;
}


.doorway__logo-box {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;      /* the side logos sit down against their face … */
  width: 100%;
  cursor: pointer;
}

/* … the Vantage box IS its dropdown face (Pete, 2026-09-27): no button under it, no caret; it
   stretches from the banner's top to the bottom line the other faces sit on and the lockup
   fills it; it lights like a button under the hand */
.doorway--big .doorway__logo-box {
  flex: 1 1 auto;
  align-self: stretch;
  position: relative;
  background: var(--card);
  border: var(--border);
  padding: var(--pad);
  width: auto;
}
.doorway--big .doorway__logo-box:hover { background: var(--card-hover); }
/* the lockup fills the box (banner.js sizes --lk from the box's inner height); no caret */
.doorway--big .doorway__logo-box { overflow: hidden; }
.doorway--big .lockup { flex: 0 0 auto; }



/* Logos size off the type scale, never a pixel count. */
.doorway__logo { height: var(--t-page); width: auto; max-width: 100%; display: block; }
.doorway__logo--wide { height: var(--t-section); }
/* The Egan SVG carries the grid and the "Building on Promises Kept" strap in its box, so at
   a given height the EGAN letters come out small. Scaled so the LETTERS match the others. */
.doorway__logo--egan { height: calc(var(--t-page) * 1.45); }

/* The user's own doorway: their avatar — a drawn one from a seed, or a photo — or their
   initials until they have chosen. Sized like the logos. */
.user-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(var(--t-page) * 1.3);
  width: calc(var(--t-page) * 1.3);
  background: var(--card);
  font-size: var(--t-card);
  font-weight: 700;
  color: var(--text);
  overflow: hidden;
}
.user-mark > svg, .user-mark > img { width: 100%; height: 100%; display: block; object-fit: cover; }
/* The Google photo is a circle, as Google shows it — the one round thing on the site, and
   left out of the shape observer for that reason. */
.user-mark--google { border-radius: 50% !important; }

/* Avatar and name side by side in the banner. */
.user-id { display: flex; align-items: center; gap: var(--pad); min-width: 0; }
.user-id__name { font-size: var(--t-label); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* My Account — the avatar chooser */
.avatars { display: flex; flex-wrap: wrap; gap: var(--gap); }
.avatars__pick {
  width: calc(var(--t-page) * 2.2);
  height: calc(var(--t-page) * 2.2);
  padding: 0;
  border: var(--border);
  background: var(--card);
  cursor: pointer;
  overflow: hidden;
}
.avatars__pick > svg, .avatars__pick > img { width: 100%; height: 100%; display: block; object-fit: cover; }
.avatars__pick:hover { background: var(--card-hover); }
.avatars__pick.is-selected { border: var(--selected-border); }
.avatars__pick--google, .avatars__pick--google > img { border-radius: 50%; }
.file { position: absolute; width: 1px; height: 1px; opacity: 0; }  /* the label is the button */
/* Solway: the rays are most of the image's height, so the sun-and-name is scaled past them.
   Otter Tail: the "Power Company" strap is ignored the same way. */
.doorway__logo--solway { height: calc(var(--t-page) * 1.6); }
.doorway__logo--ottertail { height: calc(var(--t-page) * 1.35); }

/* No pad behind anyone's logo (Pete, 2026-09-18). A navy raster on the 18% ground is lifted
   by a brightness filter in dark mode only — it stays its own colours, just lighter. */
:root:not([data-mode='light']) .doorway__logo--raster { filter: brightness(1.9); }
@media (prefers-color-scheme: light) {
  :root:not([data-mode='dark']) .doorway__logo--raster { filter: none; }
}
:root[data-mode='light'] .doorway__logo--raster { filter: none; }
.doorway__logo--lead { height: var(--t-page); }
/* THE LOCKUP — mark left of wordmark, vertically centred, at the brief's ratios
   (mark 88 : wordmark 60 : gap 22). Italiana for the wordmark and the mark's V. Larger than
   everything else in the row. */
.lockup {
  --lk: calc(var(--t-page) * 1.2);         /* the wordmark size; everything else is a ratio of it */
  display: inline-flex;
  align-items: center;
  gap: calc(var(--lk) * 22 / 60);
  color: var(--text);
  white-space: nowrap;
}
.lockup__mark { height: calc(var(--lk) * 88 / 60); width: auto; display: block; }
.lockup__word {
  font-family: 'Italiana', serif;
  font-weight: 400;
  font-size: var(--lk);
  letter-spacing: 0.02em;
  line-height: 1;
  display: inline-flex;
  align-items: baseline;
}
.lockup__g {
  width: 0.73em;
  height: 0.83em;
  margin: 0 -0.01em 0 -0.02em;
  transform: translateY(0.065em);
  display: inline-block;
}

.doorway__face {
  width: 100%;
  font-size: var(--t-small);
  padding: var(--pad);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The list drops below the face, over the rows beneath. Scrolls past a dozen lines. */
.doorway__list,
.deck__list,
.dropdown__list {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 100%;
  max-height: calc(var(--t-small) * var(--lh) * 14);
  overflow-y: auto;
  z-index: 5;
  background: var(--card);
  border: var(--border);
  padding: var(--pad);
  margin-top: calc(var(--pad) / 4);
}

.doorway__entry {
  display: block;
  width: 100%;
  text-align: left;
  font-size: var(--t-small);
  padding: var(--pad);
  background: none;
  border: 0;
  color: var(--text);
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.doorway__entry:hover { background: var(--card-hover); }
.doorway__entry--head { font-weight: 700; }
.doorway__entry--rule { color: var(--text2); cursor: default; }


/* ---------- row 3 — navigation, and the deck ---------- */

.nav {
  justify-content: space-between;
}

.nav__group {
  display: flex;
  align-items: center;
  gap: var(--pad);
  min-width: 0;
}

.nav__jump {
  font-size: var(--t-body);
  width: auto;
  white-space: nowrap;
}

/* The back button names where it goes, and carries one of the site's two
   sanctioned icons (Addendum H §7b). */
.back {
  display: flex;
  align-items: center;
  gap: calc(var(--pad) / 2);
  width: auto;
  font-size: var(--t-body);
  white-space: nowrap;
}

/* The deck holds the cascade history with back and forward. Being a control
   rather than a place, it works identically on mobile where there is no left
   column. Opening it SWAPS the face for the list inside the same height — the
   row does not grow, so nothing below it moves. */
.deck {
  position: relative;
  display: flex;
  align-items: stretch;
  gap: calc(var(--pad) / 2);
  min-width: 0;
  flex: 1 1 auto;
}

.deck__face {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  font-size: var(--t-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.deck__step {
  width: auto;
  flex: 0 0 auto;
}

.deck__entry {
  white-space: nowrap;
  display: block;
  width: 100%;
  text-align: left;
  font-size: var(--t-body);
  padding: var(--pad);
  background: none;
  border: 0;
  color: var(--text);
  font-family: inherit;
  cursor: pointer;
}

.deck__entry:hover { background: var(--card-hover); }
.deck__entry[aria-current='true'] { border: var(--selected-border); background: var(--card-selected); }

/* ---------- row 4 — tools ---------- */

.tools {
  gap: var(--pad);
}

/* Icons live here and on the back button, nowhere else. A mark scans faster
   than a word where the same action repeats all day. */
.tool {
  display: flex;
  align-items: center;
  gap: calc(var(--pad) / 2);
  width: auto;
  flex: 1 1 auto;
  justify-content: center;
  font-size: var(--t-body);
  white-space: nowrap;
}

.tool__icon {
  width: var(--t-label);
  height: var(--t-label);
  flex: 0 0 auto;
  display: block;
}

/* One line under the row rather than five lines wedged between five buttons.
   Still the no-disabled rule: the controls keep their normal look and a short
   line says what is not ready. */
.tools__why {
  width: 100%;
  font-size: var(--t-small);
  color: var(--text2);
  /* One line, always. The full sentence goes to the dialogue box; this line must not
     wrap to two at phone width, because that is the strip growing. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: var(--lh);
}

/* ---------- collapsed furniture rows (dropdown.js) ---------- */

/* The height is pinned in JS to whatever the face measured, so opening one of these can
   never make the pinned strip taller. Everything below it stays exactly where it was. */
.dropdown {
  position: relative;
  display: flex;
  align-items: stretch;
  gap: var(--pad);
  flex: 1 1 auto;
  min-width: 0;
}

.dropdown__face {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  font-size: var(--t-body);
}

.dropdown__group { position: relative; display: flex; flex: 1 1 auto; min-width: 0; }
.dropdown__group > .dropdown__wide { width: 100%; }
.dropdown__group > .dropdown__list { min-width: 100%; white-space: nowrap; }

.dropdown__wide {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--pad) / 2);
  font-size: var(--t-body);
  white-space: nowrap;
}


.dropdown__entry {
  display: flex;
  align-items: center;
  gap: calc(var(--pad) / 2);
  width: 100%;
  text-align: left;
  font-size: var(--t-body);
  padding: var(--pad);
  background: none;
  border: 0;
  color: var(--text);
  font-family: inherit;
  cursor: pointer;
}

.dropdown__entry:hover { background: var(--card-hover); }

.dropdown__entry > svg { flex: 0 0 auto; width: var(--t-label); height: var(--t-label); }

/* The Vantage mark leads the banner, so it is the one logo at full step. */
.doorway__logo--lead { height: var(--t-page); }
/* THE LOCKUP — mark left of wordmark, vertically centred, at the brief's ratios
   (mark 88 : wordmark 60 : gap 22). Italiana for the wordmark and the mark's V. Larger than
   everything else in the row. */
.lockup {
  --lk: calc(var(--t-page) * 1.2);         /* the wordmark size; everything else is a ratio of it */
  display: inline-flex;
  align-items: center;
  gap: calc(var(--lk) * 22 / 60);
  color: var(--text);
  white-space: nowrap;
}
.lockup__mark { height: calc(var(--lk) * 88 / 60); width: auto; display: block; }
.lockup__word {
  font-family: 'Italiana', serif;
  font-weight: 400;
  font-size: var(--lk);
  letter-spacing: 0.02em;
  line-height: 1;
  display: inline-flex;
  align-items: baseline;
}
.lockup__g {
  width: 0.73em;
  height: 0.83em;
  margin: 0 -0.01em 0 -0.02em;
  transform: translateY(0.065em);
  display: inline-block;
}

/* On a phone the back button, the deck and the far-jumps control share one line rather than
   wrapping onto two — the deck face is the one that gives up width, because its name is the
   one thing already repeated on the page you are looking at. */
@media (max-width: 45rem) {
  .nav { flex-wrap: nowrap; }
  .nav__group { min-width: 0; flex: 1 1 auto; }
  /* The back button names its destination, so it is the one control that must never be
     clipped — "Back to Ega" is worse than no label. It keeps its full width and the deck
     face gives up whatever is needed, because the deck is showing you the name of the
     place you are already looking at. */
  .back { flex: 0 0 auto; }
}

/* ---------- My Account → Site Design (account.js) ---------- */

.row-between {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--gap);
}

.choice {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pad);
}

.choice > .btn { width: auto; flex: 1 1 auto; }

/* The one native control on the site. Its track and thumb take the ladder's colours; it
   is sized in em so it scales with the type like everything else. */
.range {
  width: 100%;
  margin: 0;
  accent-color: oklch(calc(var(--btn-l) * 1%) var(--btn-c) var(--btn-h));
  height: 1.5em;
}

/* Hover style — Addendum H §7, three ways (Pete, 2026-09-27). Tonal is the default and is
   defined on .btn: one rung lighter. Physical is a lift with a shadow and the colour as it
   was. Combined is both. The shadow is drawn outside the box and moves no neighbour. */
:root[data-hover='physical'] .btn:hover {
  --lift: 0;
  box-shadow: var(--glow), 0 0.25em 0.75em oklch(0% 0 0 / 0.4);
}
:root[data-hover='combined'] .btn:hover {
  box-shadow: var(--glow), 0 0.25em 0.75em oklch(0% 0 0 / 0.4);
}

/* Phone: the banner stacks — Vantage first, then the sides — until the worker site is
   taken up again. Admin is the focus (Pete, 2026-09-18). */
@media (max-width: 45rem) {
  .banner { grid-template-columns: 1fr; justify-items: center; }
  .banner > .doorway--big { order: -1; }
  .banner__side { width: 100%; justify-content: center; }
  .lockup { --lk: var(--t-page); }
}

/* ---------- login (login.js) ---------- */
.login { align-items: center; text-align: center; padding: var(--gap); max-width: 40rem; margin: 0 auto; }
.login__lockup { --lk: calc(var(--t-page) * 1.4); padding-top: var(--gap); }
.login__line { max-width: 34rem; }
/* (v45) the crew sign-in under the Egan button: left-aligned fields, the line under Sign in two lines high whatever it says */
.login__crew { text-align: left; width: 100%; max-width: 28rem; }
.login__crew .crewsign__in { width: 100%; }
.login__crewline { min-height: calc(var(--lh, 1.4) * 4em); margin: 0; }
.login__tap { min-height: calc(var(--lh, 1.4) * 2em); margin: 0; }   /* (v67) Google's one-tap as it stands — two lines' room always */
/* (v47) OUTSIDE EVERY PLACE A CREW MAY USE VANTAGE: the whole screen, the page kept under it as it was (inert), back
   the moment the phone is inside — a crew sign-in's phone only (crewfence.js) */
.crewlock { position: fixed; inset: 0; z-index: 1000; overflow: auto; background: var(--bg); color: var(--text); display: flex; flex-direction: column; justify-content: center; }
.crewlock > .login { width: 100%; }
.crewlock__line { margin: 0; min-height: calc(var(--lh, 1.4) * 3em); }   /* four lines: the longest thing it says, on a phone */
/* Crew Sign-In (#crew-signin) and Your Password (#password) */
/* (v46) their boxes: one line, the size and look of the site's own picks */
.crewsign__in { width: 100%; font: inherit; font-size: var(--t-body); line-height: var(--lh); padding: var(--pad); background: var(--card); color: var(--text); border: var(--border); border-radius: var(--radius-cap); min-width: 0; }
.crewsign__in::placeholder { color: var(--text2); }
.crewsign__roster { max-height: 24rem; overflow-y: auto; gap: 0.15rem; }   /* (v59) */
.crewsign__roster:empty { display: none; }
.crewsign__rosterline { margin: 0; }
.crewsign__paste { resize: vertical; min-height: 6rem; }
.crewsign__who { padding: calc(var(--pad) * 0.5) var(--pad); gap: calc(var(--pad) * 0.4); }   /* (v60) a person: two lines */
.crewsign__wholine { display: flex; align-items: center; gap: var(--pad); min-width: 0; }
.crewsign__wholine h4 { margin: 0; flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--t-body); }
.crewsign__acts .crewsign__stands { white-space: nowrap; }
.crewsign__wholine .crewsign__un { text-transform: none; font-weight: 400; color: var(--text2); }
.crewsign__wholine .crewsign__tier { flex: 0 0 auto; width: auto; font-size: var(--t-small); padding-block: calc(var(--pad) * 0.3); }
.crewsign__acts { align-items: center; }
.crewsign__acts .crewsign__reset { flex: 0 0 11rem; width: 11rem; font-size: var(--t-small); padding-block: calc(var(--pad) * 0.3); }
.crewsign__line { margin: 0; min-height: calc(var(--lh, 1.4) * 1em); }
.crewsign__said { margin: 0; min-height: calc(var(--lh, 1.4) * 1em); }
.crewsign__row { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: flex-start; gap: var(--pad); }
.crewsign__row > .crewsign__in, .crewsign__row > .pick { width: auto; flex: 1 1 12rem; min-width: 0; }   /* (v46) only a box standing in the row itself: one inside a label's column grew 12rem TALL */
.crewsign__field { flex: 1 1 12rem; min-width: 0; }
.crewsign__field .crewsign__in, .crewsign__field .pick { width: 100%; }
.crewsign__make { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: var(--pad); align-items: end; }
.crewsign__list { min-width: 0; }
.crewsign__table { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.crewsign__table th, .crewsign__table td { text-align: left; padding: calc(var(--pad) / 3) calc(var(--pad) / 2); border-bottom: var(--border); }
.crewsign__table tr[data-ok='false'] td:nth-child(4) { color: var(--light-red); }
.crewsign__table tr[data-ok='true'] td:nth-child(4) { color: var(--light-green); }
@media (max-width: 40rem) { .crewsign__table td:nth-child(5), .crewsign__table th:nth-child(5) { display: none; } }

/* ---------- import (import.js) ---------- */
.checks { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); }
.check { display: flex; align-items: center; gap: var(--pad); font-size: var(--t-body); cursor: pointer; }
.check input { width: 1.2em; height: 1.2em; accent-color: oklch(calc(var(--btn-l) * 1%) var(--btn-c) var(--btn-h)); }

/* The Drive file picker: two columns of tiles, a spreadsheet mark on each. */
.files { display: grid; grid-template-columns: 1fr 1fr; gap: var(--pad); }
.file-tile {
  display: flex; align-items: center; gap: var(--pad); text-align: left;
  padding: var(--pad); background: var(--card); border: var(--border);
  color: var(--text); font: inherit; cursor: pointer; min-width: 0;
}
.file-tile:hover { background: var(--card-hover); }
.file-tile.is-selected { border: var(--selected-border); background: var(--card-selected); }
.file-tile > svg { width: var(--t-section); height: var(--t-section); flex: 0 0 auto; }
.file-tile__text { display: flex; flex-direction: column; min-width: 0; }
.file-tile__name { font-size: var(--t-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 45rem) { .files { grid-template-columns: 1fr; } }

/* ---------- the sheet, drawn exactly (grid.js) ----------
   Every fill, font, colour, alignment and border on a cell is inline, from the sheet itself.
   Here is only the paper, the sheet's own default type, the on-screen gridline, and the mark
   for a column being chosen. Pixel widths and heights ARE the sheet's own numbers — a
   spreadsheet is measured in pixels — and this table is the one place they are allowed. */
.sheet-wrap { overflow: auto; height: var(--sheet-picker-height); background: var(--sheet-paper); border: var(--border); }
.sheet-wrap--fit { height: auto; max-height: var(--sheet-picker-height); }
.sheet-wrap.scrolls { overflow-x: scroll; }
.sheet { border-collapse: separate; border-spacing: 0; table-layout: fixed; background: var(--sheet-paper); color: var(--sheet-ink); font-family: var(--sheet-font); font-size: var(--sheet-size); line-height: 1.2; }
.sheet td { padding: 0; overflow: hidden; vertical-align: top; background-clip: padding-box; }
.sheet--lines td { border-right: 0.0625rem solid var(--sheet-gridline); border-bottom: 0.0625rem solid var(--sheet-gridline); }   /* only when the sheet shows gridlines */
.sheet__cell { display: flex; align-items: flex-end; justify-content: flex-start; padding: 0 0.1875rem; overflow: hidden; white-space: nowrap; }
.sheet__over { display: inline-block; overflow: hidden; white-space: nowrap; }
.sheet__frozen { background: var(--sheet-paper); }
.sheet td.sheet__task { cursor: pointer; }
.sheet td.sheet__task:hover .sheet__cell { box-shadow: inset 0 0 0 0.0625rem var(--text); }
.sheet-picks { min-height: calc(var(--t-body) * var(--lh) * 2); font-size: var(--t-body); }

/* ---------- row 6 — the map (map.js), and the cascade page (site.js) ---------- */
/* THE MAP IS DRAWN (map.js v9 — Pete, 2026-10-11: "the map is very blurry when I zoom… it should be vector… zero
   blurriness", and "the map is very slow also, there should be zero lag"). What is SEEN of a map is three canvases
   the size of its box, drawn again every frame at the screen's own sharpness: under the lines, the ground of each
   section (and a drawing that is only a picture); the plan's own LINES; over them the sheet's words, the blocks'
   frames and every name. Nothing in them is a picture being scaled, so nothing goes soft and nothing waits.
   THE STAGE is the same places as ELEMENTS, laid out where the canvas draws them and NOT SEEN (opacity 0 — still
   there for a finger, the mouse, a screen reader and the checks): the plan's box at the size it is shown — fitted,
   it is the map's box; zoomed, that many times the box — placed by map.js (left, top, width and height in the
   screen's own pixels, the one measure of a view there is). It is laid out once, when the fingers are up; while
   they are down only the canvases are drawn. The map takes every touch on it (touch-action) — one finger drags the
   view at any zoom, two zoom it — and never selects its own names. */
.map { position: relative; width: 100%; height: var(--map-height); background: var(--panel); border: var(--border); overflow: hidden; touch-action: none; overscroll-behavior: contain; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; cursor: grab; }
.map__under, .map__inks, .map__over { position: absolute; left: 0; top: 0; width: 100%; height: calc(100% - var(--map-handle)); display: block; pointer-events: none; }
/* the plan's lines take the mode's ink from here (color): light lines on the dark ground (yellow), dark lines on
   the light. --map-ink-min is the least a line is ever drawn; --map-ink-bold thickens a PICTURE of ink, as before. */
.map__inks { color: var(--map-ink, var(--text2)); }
.map__ink { position: absolute; inset: 0; display: block; width: 100%; height: 100%; pointer-events: none; }
.map__stage { position: absolute; left: 0; top: 0; width: 100%; height: calc(100% - var(--map-handle)); container-type: inline-size; opacity: 0; }
/* THE LOOKS (map.js v9): one sample of each kind of place, at the end of the page, never seen and never touched.
   What THIS stylesheet says a name, a frame or a corner looks like is read off them, and the canvas draws that —
   so the look of the map is still set here, in one place, by the same rules as before. */
.map__looks { position: fixed; left: 0; top: 0; width: 0; height: 0; overflow: hidden; visibility: hidden; pointer-events: none; contain: strict; }
/* THE TOUCH PLATE (map.js v8 — Pete, 2026-10-11: "whatever my fingers are on top of when I'm zooming should not
   affect how the zoom works"). On a phone or a tablet one clear sheet lies over the whole map, and every finger lands
   on IT — never on a block, a section, a name or the picture — so there is nothing a browser can do differently for
   one of them than for another. Which place a tap is on, the map works out from where the tap is. With a mouse there
   is no plate: the cursor is over the places themselves, and they light under it as before. */
.map__touch { display: none; position: absolute; left: 0; top: 0; right: 0; bottom: var(--map-handle); z-index: 2; touch-action: none; }
@media (pointer: coarse) { .map__touch { display: block; } }
.map--fingers .map__touch { display: block; }   /* fingers are in use on a device whose first pointer is a mouse (map.js v10): the plate is up for them until the mouse moves again */
/* ONE ZOOM (map.js v8): while a map is on the screen the browser's own pinch-zoom of the page is off everywhere on
   it — scrolling is not. Two fingers are the map's, wherever they land. */
:root[data-map-up='true'] { touch-action: pan-x pan-y; }
.map--panning, .map--panning .shape, .map--panning .shape__tag { cursor: grabbing; }
/* THE NAMES SCALE WITH THE MAP (2026-10-11): on a wide map they are the small type step, as built; on a narrow one —
   a phone, where the whole site is some 370 pixels across — they shrink with the drawing, so 112 names do not bury
   the plan they are on. Never larger than the type step. */
.map__stage .shape, .map__stage .shape__tag { font-size: min(var(--t-small), var(--map-name)); }   /* the same numbers map.js draws the names by (tokens map.nameCqw) */
.map__stage .shape--small .shape__tag { font-size: min(calc(var(--t-small) * var(--map-name-small-scale)), var(--map-name-small)); }
/* a drawing that is a picture: fetched by this element (site.js gives it its address), drawn by the canvas */
.map__drawing { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; user-select: none; -webkit-user-drag: none; }
.map__shapes { position: absolute; inset: 0; }
.map--placing .map__stage { cursor: crosshair; }
.map__hint { position: absolute; left: var(--pad); top: var(--pad); max-width: calc(100% - 2 * var(--pad)); z-index: 3; color: var(--text); background: var(--card); border: var(--border); padding: var(--pad); border-radius: var(--radius-cap); min-height: 1.4em; pointer-events: none; }
.map__hint[hidden] { display: none; }
/* (v42) a view with nothing on this map (Housekeeping, until it has a place): said in the middle of the map, never taking a tap */
.map__note { position: absolute; inset: 0; z-index: 3; display: flex; align-items: center; justify-content: center; pointer-events: none; padding: var(--pad); }
.map__note[hidden] { display: none; }
.map__note > span { background: var(--card); color: var(--text); border: var(--border); border-radius: var(--radius-cap); padding: var(--pad) calc(var(--pad) * 2); font-weight: 700; text-align: center; max-width: 100%; }
.map__handle { position: absolute; left: 0; right: 0; bottom: 0; height: var(--map-handle); background: var(--raised); border-top: var(--border); cursor: ns-resize; }
.map__handle::after { content: ''; display: block; width: 3rem; height: 0.2rem; margin: 0.35rem auto 0; background: var(--text2); border-radius: 1rem; }

/* A shape on the map IS a location: one rounded rectangle, text always present, colour is
   who (crew) and how far (opacity) — the fill is a crew token when a task has landed there. */
.shape { position: absolute; box-sizing: border-box; display: flex; align-items: center; justify-content: center; text-align: center; overflow: hidden; background: var(--shape-fill, var(--card)); border: var(--border); color: var(--text); font-size: var(--t-small); font-weight: 700; cursor: pointer; user-select: none; touch-action: none; }
.shape:hover { background: var(--card-hover); }
.shape::before { content: ''; position: absolute; inset: 0; background: var(--shape-fill, transparent); opacity: var(--done, 0); pointer-events: none; }
.shape { background: var(--card); }
.shape > * { position: relative; }
.shape--here { border: var(--selected-border); }
.shape__name { padding: 0 0.3em; overflow: hidden; max-width: 100%; max-height: 100%; line-height: 1.1; overflow-wrap: anywhere; }
/* EDITING IS A BUTTON (Pete, 2026-10-11: "if I want to edit the map, that should be a button push, not the default").
   Until Edit map is pressed a place cannot be moved or sized: no corner to drag is drawn, and a drag on a place moves
   the view. With it pressed (map--editing) every place shows its box and its corner. */
.shape__grip { display: none; position: absolute; right: 0; bottom: 0; width: 1rem; height: 1rem; background: var(--text2); cursor: nwse-resize; border-radius: var(--radius-cap) 0 0 0; }
.map--editing .shape__grip { display: block; z-index: 3; }   /* over an LBD's name: every section has one at this corner */
.map--editing .shape, .map--editing .shape__tag { cursor: move; }
.map--editing .shape--mask { outline: var(--border); outline-style: dashed; }
/* a location's real outline (map.js v2): its ground is drawn by the canvas — the section's true outline from the
   plan, in the crew's colour, as strong as it is far done (tokens map.fill) — and the tag carries the name */
.shape--mask, .shape--frame, .shape--sub, .shape--area, .shape--row { background: transparent; border: none; overflow: visible; border-radius: 0; }
.shape--sub .shape__tag { top: 25%; }   /* (v55) as map.js draws it — clear of the LBD's tag across its middle */
.shape--mask:hover, .shape--frame:hover, .shape--sub:hover, .shape--area:hover, .shape--row:hover { background: transparent; }
.shape--mask::before, .shape--frame::before, .shape--sub::before, .shape--area::before, .shape--row::before { display: none; }
.shape--row { z-index: 1; }   /* (v56) a subsection's rows over the subsection they are in — a tap on one is that row's */
.shape__tag { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); background: var(--card); border: var(--border); color: var(--text); padding: 0.05em 0.45em; white-space: nowrap; line-height: 1.3; font-size: var(--t-small); }
.shape--mask:hover .shape__tag, .shape--frame:hover .shape__tag, .shape--small:hover .shape__tag { background: var(--card-hover); }
/* a second line under a place's name — a section's own % (V3) — smaller, in the second ink. map.js reads these very
   numbers off a sample and draws the line by them; the element here is what a tap is found on. */
.shape__sub { display: block; font-size: calc(1em * var(--map-sub-scale)); font-weight: 400; line-height: 1.15; color: var(--text2); }
.shape--here .shape__tag { border: var(--selected-border); }
/* a block: an outline, its button at the top-left corner; the sections inside stay clickable */
/* A BLOCK'S BUTTON IS OVER ITS SECTIONS (2026-10-11): a section's box reaches up under the block's name, and being
   later on the page it took the tap meant for the block — on a phone, where the name is a large part of the block,
   most of them. The block's NAME is lifted one step — under the inverters and LBDs, which stay on top (2). The
   frame itself is not lifted, so the corner it is sized by can come out over everything while editing (3). */
.shape--frame { pointer-events: none; outline: 0.15rem dashed var(--text2); outline-offset: 0.2rem; }
.shape--frame .shape__tag { z-index: 1; pointer-events: auto; left: 50%; top: 0; transform: translate(-50%, -55%); }
.shape--frame .shape__grip { pointer-events: auto; }
/* the small buttons — an inverter, an LBD — sit ON the sections, so they come out on top */
.shape--small { z-index: 2; background: transparent; border: none; overflow: visible; border-radius: 0; }
.shape--small::before { display: none; }
.shape--small .shape__tag { font-size: calc(var(--t-small) * var(--map-name-small-scale)); padding: 0.05em 0.35em; }
.shape--inverter .shape__tag { background: var(--crew-amber-a); color: var(--crew-a-ink); border-color: var(--crew-a-ink); }
.shape--lbd .shape__tag { background: var(--crew-blue-a); color: var(--crew-a-ink); border-color: var(--crew-a-ink); }
.shape--small .shape__grip, .map--editing .shape--small .shape__grip { display: none; }
.shape--small .shape__sub { color: inherit; }   /* (v25) an inverter's or an LBD's % — in its tag's own ink, as map.js draws it */

.btn--quiet { --lift: -6; }
.footer { display: flex; justify-content: space-between; gap: var(--gap); font-size: var(--t-small); color: var(--text2); padding: var(--pad); }

/* Below the desktop breakpoint the map sits above the panel at full width. The panel keeps
   its place first in the DOM either way (H §7f). The desktop grid is declared earlier. */
@media (max-width: 59.99rem) {
  .wrap { display: flex; flex-direction: column; gap: var(--gap); width: 100%; }
  .wrap > .context { order: 1; }
  .wrap > .column { order: 2; }
  /* the home screen on a phone: the tasks first and foremost, the site map under them (Pete, 2026-09-26) */
  .wrap--tasks-first > .column { order: 1; }
  .wrap--tasks-first > .context { order: 2; }
}

/* ---------- drawings (drawings.js): the Forma browser and the drawing view ---------- */
.crumbs { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); align-items: center; font-size: var(--t-body); min-height: calc(var(--t-body) * var(--lh) * 1.6); }
.crumb { background: none; border: 0; padding: 0; color: var(--text2); font: inherit; cursor: pointer; }
.crumb:hover { color: var(--text); }
.crumb--here { color: var(--text); font-weight: 700; cursor: default; }
.file-tile--folder { background: var(--raised); }
.file-tile--dim .file-tile__name { color: var(--text2); }
.drawing-view { width: 100%; aspect-ratio: 4 / 3; background: var(--sheet-paper); border: var(--border); overflow: auto; }
.drawing-view canvas, .drawing-view img { display: block; width: 100%; height: auto; }
.drawing-tile { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); background: var(--card); border: var(--border); padding: var(--pad); color: var(--text); text-decoration: none; min-width: 0; }
.drawing-tile:hover { background: var(--card-hover); }
.drawing-tile__name { font-size: var(--t-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- a dropdown as a control (task.js Block / Section): the card's colours, room for
   its text. (It had borrowed the dialogue box's input style, whose padding left two pixels
   for the text at the select's own height — the choice was there and could not be seen.) */
.pick { width: 100%; font: inherit; font-size: var(--t-body); line-height: var(--lh); padding: var(--pad); background: var(--card); color: var(--text); border: var(--border); border-radius: var(--radius-cap); cursor: pointer; }
.pick:focus-visible { outline: var(--selected-border); outline-offset: calc(var(--pad) / 4); }
.pick option { background: var(--card); color: var(--text); }

/* ---------- count entry (counts.js): the one input, at the top of the page ---------- */
.count-entry__grid { display: grid; grid-template-columns: auto 1fr; gap: calc(var(--pad) / 2) var(--pad); align-items: center; }
.count-entry__grid .dialogue__input { width: 100%; }

/* ---------- the card return path (paper.js) ---------- */
.card-photo { display: block; width: 100%; height: auto; border: var(--border); }

/* ---------- switches (task.js): a name and a track with a knob — the form's settings ---------- */
.switches { display: flex; flex-wrap: wrap; gap: var(--pad) var(--gap); align-items: center; }
.switch { display: inline-flex; align-items: center; gap: calc(var(--pad) / 2); background: none; border: 0; padding: 0; color: var(--text2); font: inherit; font-size: var(--t-body); cursor: pointer; }
.switch__name { white-space: nowrap; }
.switch.is-on .switch__name { color: var(--text); font-weight: 700; }
.switch--two .switch__name--left { color: var(--text); font-weight: 700; }
.switch--two.is-on .switch__name--left { color: var(--text2); font-weight: 400; }
.switch__track { position: relative; width: 2.6em; height: 1.4em; background: var(--raised); border: var(--border); flex: 0 0 auto; }
.switch__knob { position: absolute; top: 0.15em; left: 0.15em; width: 1em; height: 1em; background: var(--text2); }
.switch.is-on .switch__track { background: oklch(calc(var(--btn-l) * 1%) var(--btn-c) var(--btn-h)); }
.switch.is-on .switch__knob { left: auto; right: 0.15em; background: var(--text); }
.switch--two.is-on .switch__track, .switch--two .switch__track { background: var(--raised); }
.switch--two .switch__knob, .switch--two.is-on .switch__knob { background: var(--text); }

/* ---------- a page with its controls in a column on the right (task.js) ----------
   Pete, 2026-09-26: the buttons off to the side, a quarter of the width. On a phone the column
   comes first — every input at the top of its page — and the pages follow. On the desktop the
   column sits to the right and stays in reach under the strip while the pages scroll. */
.side { display: flex; flex-direction: column; gap: var(--gap); width: 100%; }
.side__aside { width: 100%; }
.side__main { width: 100%; min-width: 0; }
.side__aside .switches { flex-direction: column; align-items: flex-start; }
.side__aside .switches > .row-between { width: 100%; }
.switch-row { display: flex; align-items: center; gap: var(--pad); width: 100%; }
.switch-row > .switch { flex: 1 1 auto; min-width: 0; }
.btn--small { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: var(--pad); }
.side__aside .switch { align-items: flex-start; max-width: 100%; }
.side__aside .switch__name { white-space: normal; text-align: left; }   /* a long task name wraps in the column rather than scrolling it sideways */
/* THE VIEWER (task.js viewer()): the pages as their own page inside the page. A bar with the
   zoom controls, then a box with a scrollbar you can SEE — wide, a track, a solid thumb — that
   scrolls both ways when the page is zoomed past its width. On the desktop the box is the
   height of the screen under the strip and stays put while the browser's own scrollbar moves
   the column on the right (Pete, 2026-09-26: two sliders). On a phone it is three-quarters of
   the screen tall and sits in the page's flow under the column. */
.viewer { display: flex; flex-direction: column; gap: var(--pad); width: 100%; min-width: 0; }
/* HEADERS STAY PUT (Pete, 2026-09-26 — "a firm and fast rule for anything I design"): a block's
   header sticks to the top of the scrolling box while its sections scroll under it, and each
   section's header sticks just under the block's. The box scrolls; the headers do not. */
.viewer__box .block__head { position: sticky; top: 0; z-index: 3; background: var(--panel); display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); max-width: 100%; min-width: 0; }
.block__head > h2 { flex: 1 1 auto; min-width: 0; margin: 0; }
.block__head .block__section { font-weight: 400; color: var(--text2); }
/* (v18) THE PDF'S HEADER IS BLOCK · SECTION — the two dropdowns where the words were, in the heading's own size: the
   block in its weight, the section in the lighter one, as the words were; each as wide as what it says */
.block__picks { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2); }
.block__pick { width: auto; min-width: 0; max-width: 100%; font: inherit; line-height: var(--lh); padding: calc(var(--pad) / 4) calc(var(--pad) / 2); background: transparent; }
.block__pick--section { font-weight: 400; color: var(--text2); }
.area__note { margin: 0; color: var(--text2); }
.block__tally { flex: 0 1 auto; white-space: nowrap; }
.block__tally b { font-weight: 700; color: var(--text); }
.viewer__controls { flex: 0 1 auto; flex-wrap: wrap; min-width: 0; max-width: 100%; }
/* the map as the input (task.js v16): the map where the pages were, the chosen section's rows
   under it as live cells — date and crew size per task, the same boxes the form has */
.mapview { display: flex; flex-direction: column; gap: var(--gap); width: 100%; min-width: 0; }
.mapview > * { flex: 0 0 auto; }   /* nothing shrinks — a flex child with its own overflow would squash to nothing; the view scrolls instead */
@media (min-width: 60rem) { .side__main > .mapview { overflow: auto; } }

/* THE ENTRY PAGE, ONE COLUMN (task.js, Pete 2026-09-27): the filters block on top — crews (a grid,
   five to a row at most, the crew you are in marked), Date, Block, Section, the tasks on the form —
   then the Map | PDF toggle, then the view full width, then printing and the rest under it */
.entry { width: 100%; }
/* THE HEADER NEVER SCROLLS (Pete, 2026-09-27, a site rule): it is pinned under the strip, and on the desktop the
   view under it is sized to the foot of the screen and scrolls inside itself — nothing sits under the view */
.entry__filters { width: 100%; position: sticky; top: calc(var(--strip-height, 0px) + var(--gap)); z-index: 2; background: var(--panel); gap: var(--pad); }   /* rows inside the one shape sit a padding apart, not a gap */
.entry__title { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--pad) calc(var(--pad) * 2); width: 100%; }
.entry__title > h3 { margin: 0; }
/* the cascade's top row: the views, each with its crew count */
.entry__views { display: flex; flex-wrap: wrap; gap: var(--pad); width: 100%; }
.entry__views > .btn { width: auto; flex: 1 1 auto; }
.entry__row { display: flex; flex-wrap: wrap; gap: var(--pad); align-items: flex-end; }
.entry__field { display: flex; flex-direction: row; align-items: center; gap: calc(var(--pad) / 2); flex: 1 1 12rem; min-width: 0; }   /* the label beside its box: one line, a shorter header */
.entry__field > label { flex: 0 0 auto; white-space: nowrap; }
.entry__field .pick, .entry__field .entry__date { flex: 1 1 auto; width: auto; min-width: 0; }
.entry__date { position: static; width: 100%; height: 2.4em; font-size: var(--t-label); padding: 0 var(--pad); background: var(--raised); color: var(--text); border: var(--border); }
.entry__filters .switches { display: flex; flex-wrap: wrap; gap: var(--pad); align-items: center; }
.entry__filters .switches > .row-between { width: auto; flex: 0 1 auto; gap: var(--pad); }   /* the label and All flow with the switches, one line when it fits */
.entry__filters .switch-row { width: auto; flex: 0 1 auto; }
.viewtoggle > .btn { width: auto; flex: 0 0 auto; }
/* the header's bar: Print | Export with its format and buttons, then the actions (the Map | PDF switch is up on the title line) */
.entry__bar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--pad); width: 100%; }
.entry__print { display: flex; flex-wrap: wrap; align-items: center; gap: var(--pad); }
.entry__print > .btn { width: auto; flex: 0 0 auto; }
.entry__print > .pick { width: auto; flex: 0 0 auto; }
/* Undo, Inbox, Text Crew, Design the card — in the header's bar, never under the view */
.entry__acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--pad); }
.entry__acts > .btn, .entry__acts > a.btn { width: auto; flex: 0 0 auto; }
.entry__note { align-self: flex-start; }
.entry__view { width: 100%; min-width: 0; display: flex; flex-direction: column; gap: var(--gap); }
/* the one map, embedded in the entry: the Up control above it names where it goes */
.atlas { width: 100%; min-width: 0; container-type: inline-size; container-name: atlas; }
/* the bar over the map: its LEAD on the left — the Draw | List switch where there is a list (v15, below), then where
   Up goes (or, at the top, what a tap does); the map's own controls —
   Zoom out · Zoom in · Fit, and Edit map for those who may — to the right of it; on a phone, on the line under it,
   from the left. THE MAP UNDER THE BAR NEVER MOVES: the line at the top is the box of a button with nothing drawn,
   so Up taking its place changes no height; and Edit map, pressed, wears its ring AROUND itself (an outline) rather
   than a thicker border, so the bar does not grow by the ring. */
.atlas__up { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); min-height: 2.4em; flex-shrink: 0; }   /* (v47) never squeezed by what is under it */
.atlas__up > .btn, .atlas__lead > .btn { width: auto; font-size: var(--t-small); padding: var(--pad); }
/* THE LEAD (v15) is ONE LINE AT ANY WIDTH: one box — the switch, then Up or the hint — inside which nothing wraps.
   What follows the switch gives way, shortened with …, before anything could be pushed to a second line.
   AND WHERE THE BAR BREAKS IS DECIDED BY HOW WIDE THE MAP'S PAGE IS, NEVER BY WHAT THE BAR SAYS. Narrow (a phone):
   the lead has the first line to itself and the map's controls are under it. Wide: all of it is one line, the lead
   taking what the controls leave. It used to be left to the words — the bar wrapped when they did not fit — and
   "Tap a section to open it." is longer than "Up to Solway": in a band of widths the controls were under the hint
   at the top of the site and beside Up on a block, the bar a line shorter, and the map moved up a line as a block
   was tapped. (A browser with no container queries has the narrow arrangement at every width.) */
.atlas__lead { flex: 1 0 100%; min-width: 0; min-height: 2.4em; display: flex; align-items: center; gap: var(--pad); }
@container atlas (min-width: 38rem) {
  .atlas__up { flex-wrap: nowrap; }
  .atlas__lead { flex: 1 1 0; }
}
.atlas__lead > .btn { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* (v18) BLOCK · SECTION — always after the switch, on both faces, at every depth. They share what the switch leaves,
   each as wide as its words up to that share, and shorten before the line could ever wrap. */
.atlas__where { flex: 1 1 auto; min-width: 0; display: flex; align-items: stretch; gap: calc(var(--pad) / 2); }
.atlas__pick { flex: 0 1 auto; width: auto; min-width: 0; max-width: 50%; field-sizing: content; font-size: var(--t-small); padding: calc(var(--pad) * 0.7) calc(var(--pad) / 2); text-overflow: ellipsis; white-space: nowrap; }
/* a narrow phone's map page (under 21.5rem — a 375-wide screen and less): no room for the switch and both dropdowns
   whole on one line, so the dropdowns take a line of their own under the switch, half each — decided by the width,
   the same in every state, so the map under the bar never moves; never "Blo…" */
@container atlas (max-width: 21.5rem) {
  .atlas__lead { flex-wrap: wrap; row-gap: calc(var(--pad) / 2); }
  .atlas__where { flex: 1 1 100%; }
  .atlas__pick { flex: 1 1 0; max-width: none; field-sizing: fixed; }
}
/* (v56) the Wiring map: no Draw | List (its List is Racking's), and its three dropdowns — Block · LBD · Subsection — share
   the line; under 21.5rem they take it whole, a third each */
.atlas__lead--wiring .atlas__face { display: none; }
.atlas__lead--wiring .atlas__pick { max-width: 40%; }
.atlas__lead > .atlas__hint { flex: 1 1 auto; min-width: 0; line-height: var(--lh); padding: var(--pad) 0; border: var(--border); border-color: transparent; border-left: 0; border-right: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.atlas__up .map__controls > .btn { padding: var(--pad) calc(var(--pad) * 0.7); white-space: nowrap; }
.atlas__up .map__controls > .map__edit[aria-pressed='true'],
.entry__mapedit > .map__edit[aria-pressed='true'] { border: var(--border); outline: var(--selected-border); outline-offset: 0; }
/* (v64) − · + — condensed (Pete: "condense the zoom buttons a little"): a glyph each, bold, about as wide as the button is
   tall — the words' size, so the bar is exactly as tall as it was and the switch in the lead never moves between Draw and
   List; its name (Zoom out, Zoom in) is its label and title */
.atlas__up .map__controls > .map__zoom { min-width: 2.6em; padding-inline: calc(var(--pad) / 2); font-weight: 700; }
.map__controls { flex-wrap: nowrap; }
/* (v64) RACKING · WIRING — a pair, the picked one marked and ringed, the same size as the zoom's buttons. (v65) In the lead,
   before Block · Section (site.js v38 .atlas__viewsat); the zoom in the lead's own place for it, at the line's end */
.atlas__views { display: flex; flex-wrap: nowrap; gap: calc(var(--pad) / 2); flex: 0 0 auto; }
.atlas__viewsat, .atlas__ctl { display: flex; flex: 0 0 auto; align-items: center; min-width: 0; }
.atlas__viewsat:empty, .atlas__ctl:empty { display: none; }
.atlas__ctl { margin-left: auto; }
.atlas__ctl > .map__controls { flex-wrap: nowrap; }
@container atlas (max-width: 38rem) {
  /* LAYOUT 1, a phone: the switch first, on the first line — where it is in every state; the dropdowns and the zoom on the
     second. Its Wiring map has no switch: the zoom is the first line, the three dropdowns the second. A break between the
     lines (the lead's ::after, its height the gap) — where the line breaks is decided by the width, never by what is in it */
  .atlas__lead { flex-wrap: wrap; row-gap: 0; }
  .atlas__lead > .atlas__face { order: 1; }
  .atlas__lead::after { content: ''; order: 3; flex: 0 0 100%; height: calc(var(--pad) / 2); }
  .atlas__lead > .atlas__where { order: 4; flex: 0 1 auto; }
  .atlas__lead > .atlas__where > .atlas__pick { max-width: none; }   /* (each as wide as its words: half of a box as wide as its words cut the longer) */
  .atlas__ctl { order: 5; }
  .atlas__lead--wiring .atlas__ctl { order: 2; }
  .atlas__lead--wiring > .atlas__where { flex: 1 1 0; }
  .atlas__lead--wiring:not(:has(.atlas__views, .map__controls))::after { display: none; }   /* (Layout 1: an LBD, the PCS or a subsection open on Wiring — nothing on the first line, no break, no gap) */
  /* (v71) LAYOUT 2, a phone — RACKING · WIRING NEVER MOVE (Pete, 2026-10-22): the first line is Racking · Wiring at its left
     edge, then Up (something open in the map's place) or − · + · Fit (where the map stands) at its right — never both;
     the second line the dropdowns, and on Racking the Draw | List switch at its right end, after them. The same on Racking
     and on Wiring, the map, the List, a section, a subsection, an LBD, the PCS: Racking · Wiring are the same two buttons
     at the same place, the same size. */
  .atlas__lead--drawers > .atlas__viewsat { order: 1; }
  .atlas__lead--drawers > .atlas__upat { order: 2; }
  .atlas__lead--drawers > .atlas__ctl { order: 3; }
  .atlas__lead--drawers::after { order: 4; }
  .atlas__lead--drawers > .atlas__where { order: 5; }
  .atlas__lead--drawers > .atlas__face { order: 6; }
  /* the first line ONE height whatever is on it — Racking · Wiring alone (the List), with Up, with the zoom: the three are
     the dropdowns' height (their padding above and below the dropdowns'), so Racking · Wiring never shift up or down, and
     an open LBD or PCS under the bar keeps the room it had for its page's place and Completed (check:lbds part 7) */
  .atlas__up .atlas__lead--drawers :is(.atlas__views, .atlas__upat, .map__controls) > .btn { padding-block: calc(var(--pad) * 0.7); }
}
/* (v66) UP, RIGHT AFTER RACKING · WIRING — the views' size and look; "Up to " on a desk, "↑ " on a phone */
.atlas__upat { display: flex; flex: 0 0 auto; align-items: center; min-width: 0; }
.atlas__upat:empty { display: none; }
.atlas__up .atlas__upat > .btn { width: auto; font-size: var(--t-small); padding: var(--pad) calc(var(--pad) * 0.7); white-space: nowrap; }
.atlas__upbtn .atlas__uparrow, .atlas__upbtn.is-bare .atlas__upword { display: none; }
.atlas[data-upbar] :is(.sec__up, .lbd__up, .sheetview__up) { display: none; }   /* (the open place's own Up: the bar's says and presses it) */
@container atlas (max-width: 38rem) {
  .atlas__upbtn .atlas__upword { display: none; }
  .atlas__upbtn:not(.is-bare) .atlas__uparrow { display: inline; }
}
/* (v71) LAYOUT 2: DRAW | LIST LAST — after the dropdowns and the zoom, at the bar's right end (the dropdowns take the room
   between), so whatever comes and goes before it, it never moves; its words' room on the right of its box, as Racking ·
   Wiring have theirs at the left */
.atlas__lead.atlas__lead--drawers > .atlas__face { margin-left: auto; padding-right: 0; padding-left: calc(var(--pad) / 2); }   /* (two classes: over the switch's own rule below) */
.atlas__lead.atlas__lead--drawers > .atlas__face { min-height: calc(var(--lh) * 1em + var(--pad) * 1.4 + 0.125rem); }   /* (never shorter than a dropdown — on the narrowest phone it is a line of its own, with nothing to stretch to) */
@container atlas (max-width: 21.5rem) {
  /* the narrowest phone: the dropdowns a line of their own, half each (a third each on Wiring). Layout 1: the Racking map's
     zoom a third line under them. Layout 2: the zoom is on the first line beside Racking · Wiring, and on Racking the
     Draw | List switch is the third line, at its right end */
  .atlas__lead > .atlas__where { flex: 1 1 100%; }
  .atlas__lead:not(.atlas__lead--wiring, .atlas__lead--drawers) > .atlas__ctl { margin-top: calc(var(--pad) / 2); }
  .atlas__lead--drawers:not(.atlas__lead--wiring) > .atlas__face { margin-top: calc(var(--pad) / 2); }
}
.atlas__up .atlas__views > .btn { width: auto; font-size: var(--t-small); padding: var(--pad) calc(var(--pad) * 0.7); white-space: nowrap; }
.atlas__up .atlas__views > .btn[aria-pressed='true'] { border: var(--border); outline: var(--selected-border); outline-offset: -0.125rem; }   /* (v65) the ring inside its edge: on a phone the pair is first on the line, where the view's box would cut a ring outside it */
/* (v64) Edit map, at the top of the left drawer's entry header — the whole width; for anyone who may not, nothing */
.entry__mapedit { display: flex; width: 100%; }
.entry__mapedit:empty { display: none; }
.entry__mapedit > .btn { width: 100%; justify-content: center; }
.atlas .context { width: 100%; }
.entry__view > .viewer, .entry__view > .mapview { flex: 1 1 auto; min-height: 0; height: auto; }
.entry__view .viewer__box { flex: 1 1 auto; min-height: 0; height: auto; }
/* THE MAP FILLS THE VIEW (Pete, 2026-09-27): the embedded atlas takes the view's whole height, the drawing fitted
   inside it; with a section drilled to, the map keeps the upper part and the section's rows scroll in their own
   box under it, their header staying put. Nothing here has a height of its own. */
.entry__view > .mapview { overflow: hidden; }
.entry__view > .mapview > .atlas { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: var(--pad); }
.entry__view .atlas > .atlas__body { flex: 1 1 auto; min-height: 0; display: flex; gap: var(--gap); }
.entry__view .atlas .context { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.entry__view .atlas .map { flex: 1 1 auto; min-height: 0; height: auto; --map-handle: 0px; }
.entry__view .atlas .map__handle { display: none; }
/* Layout 1 on a narrow screen has no panel to fill (task.js fill): the map keeps a height of its own there, so it is
   never drawn at nothing — the blank map on a phone (Pete, 2026-10-11) */
@media (max-width: 59.99rem) { :root:not([data-layout='drawers']) .entry__view > .mapview { min-height: var(--map-height); } }

/* ---------- V3'S PROGRESS MAP (site.js v12) ----------
   THE CREWS OVER THE MAP: All Racking and V3's six crews, each chip in its crew's own colour (tokens.json
   progress.crews — the hex V3 used) — a wash of it at rest, the colour itself when it is the one the map is showing.
   They wrap; the line is the same height whatever is picked, so the map under it never moves. */
.atlas__crews { display: block; min-width: 0; flex-shrink: 0; }   /* (v44) the holder: the quiet sheet lies over it; .chiprow inside scrolls */
/* (v43 — task.js v54) over the PDF, in the main window: the view's crews, and under them the crew's tasks on the form */
.entry__picks { flex: 0 0 auto; min-width: 0; }
/* (v44) the crew's tasks at the top of the PDF's box: they flow, several to a line where they fit, and scroll away with it */
.entry__tasks .switches { display: flex; flex-wrap: wrap; gap: var(--pad) calc(var(--pad) * 1.5); align-items: center; }
.entry__tasks .switches > .row-between { width: 100%; flex: 0 0 auto; justify-content: flex-start; gap: var(--pad); }
.entry__tasks .switch-row { width: auto; flex: 0 1 auto; min-width: 0; }
.entry__crews { position: relative; display: block; min-width: 0; }
/* (v44) the chips' line: one line, sideways, no bar drawn — the wheel scrolls it sideways (chiprow.js); the outline of a
   picked chip has room inside it */
.chiprow { display: flex; flex-wrap: nowrap; align-items: center; gap: calc(var(--pad) / 3); overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; padding: 0.2rem; margin: -0.2rem; }
.chiprow::-webkit-scrollbar { display: none; }
/* (v77 — chiprow.js v3, Pete: "that crew … should just stay centered") a centred line — the crews — has half its width of room at each end, so ANY chip, the first and the last too, can stand in its middle */
.chiprow--center::before, .chiprow--center::after { content: ''; flex: 0 0 50%; height: 1px; }
.chiprow[data-more] { -webkit-mask-image: linear-gradient(to right, oklch(0 0 0) calc(100% - 2.5rem), transparent); mask-image: linear-gradient(to right, oklch(0 0 0) calc(100% - 2.5rem), transparent); }
.chiprow[data-less] { -webkit-mask-image: linear-gradient(to left, oklch(0 0 0) calc(100% - 2.5rem), transparent); mask-image: linear-gradient(to left, oklch(0 0 0) calc(100% - 2.5rem), transparent); }
.chiprow[data-more][data-less] { -webkit-mask-image: linear-gradient(to right, transparent, oklch(0 0 0) 2.5rem, oklch(0 0 0) calc(100% - 2.5rem), transparent); mask-image: linear-gradient(to right, transparent, oklch(0 0 0) 2.5rem, oklch(0 0 0) calc(100% - 2.5rem), transparent); }
.entry__none, .viewer__empty { margin: 0; }
.viewer__empty { padding: var(--pad); text-align: center; font-weight: 700; }
.atlas__crews:has(> .chiprow:empty) { display: none; }
/* (v76) the crew's tasks under the map: one line, never wrapped, one height; not shown where something stands in the map's place */
.atlas__tasks { display: block; position: relative; min-width: 0; flex: 0 0 auto; }
.atlas__tasks[hidden] { display: none; }
.taskchip { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) calc(var(--pad) * 0.6); white-space: nowrap; color: var(--chip-light-ink, var(--v3-ink)); background: var(--chip-light, color-mix(in oklab, var(--chip) 30%, var(--card))); border-color: var(--chip); box-shadow: none; }
.taskchip:hover { filter: brightness(1.06); }
.taskchip.is-selected, .taskchip[aria-pressed='true'] { background: var(--chip); color: var(--chip-ink); border: var(--border); border-color: var(--chip); outline: var(--selected-border); outline-offset: 0; }
/* (v20 — Pete, 2026-10-14: "Whenever a task or crew button is on the site it should be the color of the crew!") a chip is
   its crew's colour picked or not: V3's own light shade of the crew with V3's ink until it is picked, the crew's colour
   itself when it is — All Racking, which has no shade of its own, the page's second ink washed into the card */
.atlas__crews > .crewchip, .crewchip { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) calc(var(--pad) * 0.6); white-space: nowrap; color: var(--chip-light-ink, var(--v3-ink)); background: var(--chip-light, color-mix(in oklab, var(--chip) 30%, var(--card))); border-color: var(--chip); box-shadow: none; }
.crewchip:hover { filter: brightness(1.06); }
.crewchip.is-selected, .crewchip[aria-pressed='true'] { background: var(--chip); color: var(--chip-ink); border: var(--border); border-color: var(--chip); outline: var(--selected-border); outline-offset: 0; }   /* (never a heavier face: a chip that grew when picked could push the last one onto a new line, and the map under it down) */
/* DRAW | LIST (site.js v13 — Pete, 2026-10-13: "For the blocks - crew percent section I want that to be a separate
   view… a toggle, only when you're in map view, that switches between draw and list"). The map view has two faces,
   and the body under the bar shows ONE of them: Draw — the map (or the section open in its place), the crews over
   it; List — the Blocks · Crew % table and nothing else. No width decides it any more: the table is never beside
   the map, and is never in its place except by the switch (it was beside the map on a wide screen and behind a
   "Blocks %" chip on a narrow one — and with it up nothing but that chip went back to the map).
   THE SWITCH is the first thing in the bar's lead (above): the same node in the same place on either face and at
   any depth. Its box is as tall as the lead's line — the whole line for a thumb to land on, and no height added to
   the bar. */
.atlas__lead > .atlas__face { flex: 0 0 auto; align-self: stretch; font-size: var(--t-small); padding-right: calc(var(--pad) / 2); }
/* NOTHING IN THE SWITCH MOVES WHEN IT IS FLIPPED: the side that is up is written heavier, and a heavier word is a
   wider one — the track between the two words slid a pixel each way. Each word keeps the room of its heavy form
   (written once more, unseen, under itself), so the words, the track and whatever follows the switch stay put. */
.atlas__face .switch__name { display: inline-grid; }
.atlas__face .switch__name::after { content: attr(data-text); height: 0; overflow: hidden; visibility: hidden; font-weight: 700; }
/* THE TAP THAT OPENS A SECTION IS NOT A TAP IN IT (site.js v13 hush): a section that has just come up is QUIET for a
   moment — four tenths of a second from when it is on the screen — and while it is, every part of it that takes a
   tap, and the crews' line over it, has a clear sheet over it: the browser's own click for the tap that opened it
   (which used to land on the row under the finger and pick it) and the second tap of a double tap land on the
   sheet — on nothing. Each sheet lies INSIDE its part, so a finger on it still moves whatever that part scrolls in:
   the section up and down, its rows sideways, from the first moment. (One sheet over the whole section was tried:
   the first swipe was dead.) And each is its part's own ::after — no element, nothing drawn, nothing that moves;
   the parts are the boxes their sheets are laid in at all times, so nothing about the page changes when the
   sheets come and go but what a point of the screen is on. (Passing the parts over instead — pointer-events — had
   the browser work every one of a section's 1,500 things out again, twice a section: 20 ms where this is half
   of one.) */
.atlas__crews, .sec__map, .sec__tools, .sec__entry, .sec__progress, .lbd__tools, .lbd__entry, .lbd__progress { position: relative; }   /* (.sec__head sticks; .lbd__head and .lbd__grid are positioned in their own rules, v30) */
.atlas[data-quiet] > .atlas__crews::after, .atlas[data-quiet] .sec__head::after, .atlas[data-quiet] .sec__map::after, .atlas[data-quiet] .sec__tools::after, .atlas[data-quiet] .sec__entry::after, .atlas[data-quiet] .sec__progress::after, .atlas[data-quiet] .lbd__head::after, .atlas[data-quiet] .lbd__grid::after, .atlas[data-quiet] .lbd__tools::after, .atlas[data-quiet] .lbd__entry::after, .atlas[data-quiet] .lbd__progress::after { content: ''; position: absolute; inset: 0; z-index: 5; }
.atlas__body > .blocktable { display: none; }
.atlas[data-face='list'] > .atlas__crews { display: none; }   /* the list's columns ARE the crews */
.atlas[data-face='list'] .atlas__body > .context { display: none; }   /* (the map is not taken away — it is under, not shown — so Draw brings it straight back, in the box it had) */
.atlas[data-face='list'] .atlas__body > .blocktable { display: flex; flex: 1 1 auto; align-self: flex-start; max-width: 36rem; max-height: 100%; overflow: auto; font-size: var(--t-label); }
/* HEADERS STAY PUT (the site's rule): where the list is taller than its box — a phone on its side — it scrolls in
   the box and the crews' names stay at its top, on the ground the list stands on (site.js sets --list-ground). Each
   name's ground reaches across the hair of space to the next — exactly the grid's gap, and for the modules the
   extra they stand off by — so no figure shows through between two names as it passes under, and no name's ground
   lies over its neighbour's last letter. */
.atlas[data-face='list'] .blocktable__h { position: sticky; top: 0; z-index: 1; --g: var(--list-ground, var(--panel)); background: var(--g); box-shadow: 0.125rem 0 0 var(--g), -0.125rem 0 0 var(--g); }
.atlas[data-face='list'] .blocktable__h.blocktable__mod { box-shadow: 0.125rem 0 0 var(--g), -0.425rem 0 0 var(--g); }
.blocktable__key { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2); }
.atlas__grad { display: inline-block; width: 5rem; height: 0.6rem; border: var(--border); border-radius: var(--radius-cap); background: linear-gradient(90deg, color-mix(in oklab, var(--chip) 18%, transparent), color-mix(in oklab, var(--chip) 80%, transparent)); }

/* ---------- (v23) A BLOCK'S AREA ON ITS OWN SHEET (sheetview.js) ----------
   It stands where the map was, as a section does (the map is under it, not shown). Nothing in it is a card: the panel
   is the card. Its header is two lines at every width — Up · the place · Open, then the sheet and its zoom — so it is
   one height whatever the sheet is called; the sheet's box takes the rest, and every finger on it is the sheet's. */
.entry__view .atlas[data-sheet] .context > .map { display: none; }
.entry__view .atlas[data-sheet] .context > .sheetview { flex: 1 1 auto; min-height: 0; }
.sheetview { display: flex; flex-direction: column; gap: var(--pad); width: 100%; min-width: 0; min-height: 20rem;
  --sheet-filter: invert(1) hue-rotate(180deg); }   /* (the sheet in the mode's colours: dark paper, light lines — as the site plan is) */
@media (prefers-color-scheme: light) { :root:not([data-mode='dark']) .sheetview { --sheet-filter: none; } }
:root[data-mode='light'] .sheetview { --sheet-filter: none; }
.sheetview__head { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); flex: 0 0 auto; }
.sheetview__line { display: flex; align-items: center; gap: calc(var(--pad) / 2) var(--pad); min-width: 0; }
.sheetview__line > .btn, .sheetview__zoom > .btn { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); white-space: nowrap; }
.sheetview__title { margin: 0; font-size: var(--t-label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1 1 auto; }
.sheetview__name { flex: 1 1 auto; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); }
.sheetview__name > * { grid-area: 1 / 1; align-self: center; justify-self: start; }   /* (the name and the dropdown in one cell: one height whichever shows) */
.sheetview__name:not([data-several]) > .sheetview__pick, .sheetview__name[data-several] > .sheetview__nametext { visibility: hidden; }
.sheetview__nametext { font-weight: 700; text-transform: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.sheetview__pick { width: auto; max-width: 100%; min-width: 0; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); text-transform: none; }
.sheetview__zoom { display: flex; gap: calc(var(--pad) / 2); flex: 0 0 auto; }
/* where the header is narrow, the sheet's name has a line of its own — always, so the header is one height */
@container atlas (max-width: 37.99rem) { .sheetview__line--tools { flex-wrap: wrap; } .sheetview__name { flex: 1 0 100%; } }
/* (v30) a book page's own line stays ONE line however narrow: its name gives way with …, its buttons the header's size */
@container atlas (max-width: 37.99rem) { .sheetview__head--bare .sheetview__line--tools { flex-wrap: nowrap; } .sheetview__head--bare .sheetview__name { flex: 1 1 auto; } }
.sheetview__head--bare .sheetview__zoom > .btn { font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); width: auto; }
.sheetview__box { position: relative; flex: 1 1 auto; min-height: 0; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; cursor: grab; }
.sheetview--moving .sheetview__box { cursor: grabbing; }
.sheetview__canvas { position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: block; filter: var(--sheet-filter); }
/* (v28) A BOOK PAGE (sheetview.js v4, bare — an open LBD's or inverter's page of the DC Underground book): exactly as
   printed in either mode, never filtered, on its own white paper; as tall as the drawing's place in the LBD view */
.sheetview--book { --sheet-filter: none; --sheet-paper: var(--tab-paper); min-height: 0; height: 100%; gap: calc(var(--pad) / 2); }
.sheetview--book .sheetview__box { cursor: pointer; }
.sheetview__head--bare .sheetview__nametext { font-weight: 500; font-size: var(--t-small); }
/* (v24) THE WIRING (sheetview.js v2): one line of the block's enclosures and switches — or inverters and inputs — that
   scrolls sideways, and a line under it, a fixed height, for what was tapped. Each enclosure's (or inverter's) chips
   share a hue; the hues go round the rainbow from one group to the next. */
.sheetview__wiring { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); min-width: 0; }
.sheetview__wiring[hidden] { display: none; }
.sheetview__strip { display: flex; gap: var(--pad); overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; padding: 0.15rem 0.1rem calc(var(--pad) / 2); scrollbar-width: thin; }
.sheetview__group { display: flex; gap: calc(var(--pad) / 3); flex: 0 0 auto; }
.sheetview__chip { white-space: nowrap; padding: calc(var(--pad) / 3) calc(var(--pad) / 1.5); }
.sheetview__chip--lbd, .sheetview__chip--inverter, .sheetview__chip--pcs { font-weight: 700; }
.sheetview__chip[aria-pressed='true'] { border: var(--border); outline: var(--selected-border); outline-offset: -0.1rem; }   /* (picked: a ring, never a heavier border — the strip, and the sheet under it, never move) */
.sheetview__group:nth-of-type(6n + 1) > .btn { --bl: var(--btn-tools-l); --bc: var(--btn-tools-c); --bh: var(--btn-tools-h); }
.sheetview__group:nth-of-type(6n + 2) > .btn { --bl: var(--btn-banner-l); --bc: var(--btn-banner-c); --bh: var(--btn-banner-h); }
.sheetview__group:nth-of-type(6n + 3) > .btn { --bl: var(--btn-filters-l); --bc: var(--btn-filters-c); --bh: var(--btn-filters-h); }
.sheetview__group:nth-of-type(6n + 4) > .btn { --bl: var(--btn-status-l); --bc: var(--btn-status-c); --bh: var(--btn-status-h); }
.sheetview__group:nth-of-type(6n + 5) > .btn { --bl: var(--btn-digitools-l); --bc: var(--btn-digitools-c); --bh: var(--btn-digitools-h); }
.sheetview__group:nth-of-type(6n + 6) > .btn { --bl: var(--btn-dialogue-l); --bc: var(--btn-dialogue-c); --bh: var(--btn-dialogue-h); }
.sheetview__about { margin: 0; line-height: var(--lh); height: calc(2em * var(--lh)); overflow: hidden; overflow-wrap: anywhere; text-transform: none; }
@container atlas (max-width: 37.99rem) { .sheetview__about { height: calc(3em * var(--lh)); } }
.sheetview__said { position: absolute; left: 0; right: 0; top: 40%; margin: 0; text-align: center; pointer-events: none; }
.sheetview__said[hidden] { display: none; }
.sheetview__said .sheetview__again { pointer-events: auto; display: block; margin: calc(var(--pad) / 2) auto 0; }   /* (36.23) Try again, under the words of a sheet that would not open */
.sheetview__said .sheetview__again[hidden] { display: none; }

/* ---------- A SECTION, THE WAY V3 SHOWED IT (section.js) ----------
   It stands where the map was (the map is not taken away — it is under, not shown — so Up brings it straight back).
   Nothing in it is a card: the panel is the card. Its header stays put while the rest scrolls under it. */
.entry__view .atlas[data-open] .context > .map, .entry__view .atlas[data-subsection] .context > .map { display: none; }
.sec { display: flex; flex-direction: column; gap: var(--gap); width: 100%; min-width: 0; --tube-radius: calc(var(--tube-bar) * var(--radius-percent) / 50); }   /* (a tube's corner: the one shape's share of its width, doubled as the floor doubles a small button's — square at Roundness 0) */
.entry__view .atlas[data-open] .context > .sec, .entry__view .atlas[data-subsection] .context > .sec { flex: 1 1 auto; min-height: 0; overflow-x: hidden; overflow-y: scroll; overscroll-behavior: contain; }   /* (scroll, not auto: the track is always there, so nothing moves sideways when a longer section comes up. scrollbar-gutter: stable did the same and left the first marks of a line unpainted in Chromium) */
.sec__head { position: sticky; top: 0; z-index: 4; background: var(--panel); box-shadow: 0 0 0 0.125rem var(--panel); display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); padding-bottom: calc(var(--pad) / 2); }   /* (the shadow: a hair of the panel's own colour all round, so no sliver of what scrolls under it shows at a part-pixel edge) */
.sec__head > .sec__up { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); white-space: nowrap; }   /* (v19) Up, first — the section's own Block dropdown and chips are gone */
.sec__title { margin: 0; font-size: var(--t-label); white-space: nowrap; }
.sec__tools > .btn, .sec__acts > .btn { padding: calc(var(--pad) / 2) var(--pad); }
.sec__showrow { display: flex; min-width: 0; max-width: 100%; }
.sec__showing { font-size: var(--t-small); font-weight: 700; padding: calc(var(--pad) / 3) var(--pad); background: var(--chip); color: var(--chip-ink); min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* where the header is narrow, what is showing has a line of its own — always, so the header is one height whether it
   says "All Racking — Overall Progress" or "TTs", and nothing under it moves when a task is picked */
@container atlas (max-width: 51.99rem) { .sec__showrow { flex: 1 0 100%; } }
@supports not (container-type: inline-size) { .sec__showrow { flex: 1 0 100%; } }
.sec__body { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--gap); }
.sec__left { flex: 2 1 30rem; min-width: 0; display: flex; flex-direction: column; gap: var(--pad); }
.sec__entry { flex: 1 1 18rem; min-width: 0; display: flex; flex-direction: column; gap: var(--pad); }
/* the rows: a column each, west to east; north (pier A) at the top. They scroll sideways in their own box, the pier
   letters staying at its left edge. */
.sec__mapscroll { overflow-x: auto; overscroll-behavior-x: contain; padding: 0.25rem 0 calc(var(--pad) / 2); }   /* (room above for the ring round a picked row's number) */
.sec__map { display: flex; align-items: flex-start; gap: var(--tube-gap); width: max-content; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.sec__rail { position: sticky; left: 0; z-index: 3; flex: none; display: flex; flex-direction: column; width: 1.1rem; padding-top: calc(var(--tube-num) + 1rem); background: var(--panel); }
.sec__rail > span { height: var(--tube-unit); display: flex; align-items: center; justify-content: center; font-size: calc(var(--t-small) * 0.75); color: var(--text2); }
.sec__rail > span:last-child { height: 0.75rem; }
.tube { flex: none; width: var(--tube-col); display: flex; flex-direction: column; align-items: center; cursor: pointer; }
.tube__head { appearance: none; -webkit-appearance: none; font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0; cursor: pointer; display: flex; flex-direction: column; align-items: center; width: 100%; height: calc(var(--tube-num) + 1rem); }
.tube__num { box-sizing: border-box; width: var(--tube-num); height: var(--tube-num); display: flex; align-items: center; justify-content: center; font-size: calc(var(--t-small) * 0.9); font-weight: 500; background: var(--card); color: var(--text); border: var(--border); }
.tube__type { height: 0.625rem; margin-top: 0.125rem; font-size: calc(var(--t-small) * 0.66); font-weight: 500; letter-spacing: 0.03em; line-height: 0.625rem; color: var(--text2); }
/* a row's number, by its type — as V3 drew it: extra-heavy dark with a red number, light-exterior grey, light-interior plain */
.tube--XH .tube__num { background: var(--v3-ink); color: var(--v3-xh); border-color: var(--v3-xh); }
.tube--XH .tube__type { color: var(--v3-xh); }
.tube--LE .tube__num { background: var(--v3-le); color: var(--v3-paper); border-color: var(--v3-le); }
.tube.is-selected .tube__num, .tube__head:focus-visible .tube__num { outline: var(--selected-border); outline-offset: 0.0625rem; }
.tube.is-selected .tube__bar { outline: var(--selected-border); outline-offset: 0.0625rem; }
.tube__zone { position: relative; width: var(--tube-bar); margin-bottom: 0.25rem; }
.tube__bar { position: relative; display: flex; flex-direction: column; width: var(--tube-bar); border-radius: var(--tube-radius); }
/* a torque tube: one pier bay. Bare: the ground one rung up. Done: the crew's colour, set by section.js. */
.tube__bay { position: relative; display: block; height: var(--tube-unit); background: var(--raised); box-shadow: inset 0 0.0625rem 0 var(--panel); }
.tube__bay:first-child { border-radius: var(--tube-radius) var(--tube-radius) 0 0; }
.tube__bay:nth-last-child(1 of .tube__bay) { border-radius: 0 0 var(--tube-radius) var(--tube-radius); }
.tube__bay.is-done { opacity: 0.92; }
/* the day of the month, written up the tube */
.tube__day { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; transform: rotate(-90deg); font-size: calc(var(--t-small) * var(--tube-day)); font-weight: 700; letter-spacing: -0.02em; white-space: nowrap; pointer-events: none; }
.tube__damper { position: absolute; left: 50%; transform: translate(-50%, -50%); z-index: 2; font-size: calc(var(--t-small) * 0.9); font-weight: 700; line-height: 1; color: var(--v3-ink); text-shadow: 0 0 0.125rem var(--v3-paper), 0 0 0.125rem var(--v3-paper), 0 0 0.125rem var(--v3-paper); pointer-events: none; }
.tube__slew { position: absolute; left: 50%; transform: translate(-50%, -50%); z-index: 2; pointer-events: none; line-height: 1; }
.tube__slew > span { display: inline-block; background: var(--v3-ink); color: var(--v3-paper); font-size: calc(var(--t-small) * 0.62); font-weight: 700; border-radius: var(--tube-radius); padding: 0.0625rem 0.1875rem; border: 0.0625rem solid var(--v3-paper); }
.tube__slew--key, .tube__damper--key { position: static; transform: none; display: inline-block; vertical-align: middle; }
.tube__damper--key { color: var(--text); text-shadow: none; }
/* the day under the row: the latest day's, in the crew's colour when it is one task's */
/* (v58) a subsection of the Wiring map: the row's strings, and its slew drive */
.tube__string { box-shadow: inset 0 0.125rem 0 var(--panel); overflow: hidden; }
.tube__string:first-child { box-shadow: none; }
.tube__strname { position: absolute; top: 50%; left: 0; right: 0; transform: translateY(-50%); text-align: center; font-size: calc(var(--t-small) * 0.6); font-weight: 700; line-height: 1; color: var(--text2); pointer-events: none; }
.tube__strname--key { position: static; transform: none; display: inline-block; padding: 0.0625rem 0.1875rem; background: var(--raised); border-radius: var(--tube-radius, 0); vertical-align: middle; }
.tube--atslew .tube__string { opacity: 0.45; }
.tube__slew--wire { z-index: 3; }
.tube__slew--wire > span { font-size: calc(var(--t-small) * 0.72); min-width: calc(var(--tube-bar) + 0.375rem); text-align: center; padding: 0.125rem 0.1875rem; border-width: 0.125rem; }
.tube__slew--wire.is-task > span { background: var(--panel); color: var(--text); border-style: solid; }
.tube__slew--wire.is-task.is-done > span { border-color: var(--v3-paper); }
/* (v73) the Wiring map's rows are an LBD's: each circuit a band over its rows — its name on the first, a tap there picks them all */
.sec { --circ-h: 1.25rem; }
.sec[data-subsection] .sec__rail { padding-top: calc(var(--tube-num) + 1rem + var(--circ-h) + 0.125rem); }
.tube__circ { order: -1; align-self: stretch; box-sizing: border-box; display: block; position: relative; height: var(--circ-h); margin: 0 calc(-1 * var(--tube-gap)) 0.125rem 0; padding: 0; border: 0; font: inherit; color: var(--text); background: var(--raised); cursor: pointer; }
.tube__circ--b { background: var(--card); }
.tube__circ.is-last { margin-right: 0; border-top-right-radius: var(--tube-radius); border-bottom-right-radius: var(--tube-radius); }
.tube__circ.is-first { border-top-left-radius: var(--tube-radius); border-bottom-left-radius: var(--tube-radius); text-align: left; }
.tube__circ.is-marked { box-shadow: inset 0 -0.1875rem 0 var(--text); }
.tube__circname { position: relative; z-index: 2; display: inline-block; padding: 0 0.25rem; font-size: calc(var(--t-small) * 0.78); font-weight: 700; line-height: var(--circ-h); white-space: nowrap; letter-spacing: -0.01em; }
.tube__circ.is-picked .tube__circname { background: var(--text); color: var(--panel); border-radius: var(--tube-radius); }
.tube__circ:focus-visible { outline: var(--selected-border); outline-offset: 0.0625rem; }
.sec__task { flex-shrink: 1; max-width: 100%; text-align: left; }   /* (v58) a long task's name (Connect Both Sides in Split Loom) breaks onto a second line in its chip — never past the column */
.sec__head > .sec__enc { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); white-space: nowrap; }
.tube__date { height: 1rem; font-size: calc(var(--t-small) * 0.82); font-weight: 700; line-height: 1rem; white-space: nowrap; letter-spacing: -0.02em; color: var(--text); }
.sec__tools { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); }
.sec__readout { font-weight: 500; flex: 1 1 auto; min-width: 0; }
/* what the marks mean: one line that never changes, and under it what the colours mean for what is showing — two
   lines' room whatever it says, so picking a task never moves the task chips under the finger */
.sec__legend { display: flex; flex-direction: column; gap: calc(var(--pad) / 3); }
.sec__keys { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); }
.sec__keyline { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; line-height: var(--lh); height: calc(var(--t-small) * var(--lh) * 2); }
.sec__swatch { display: inline-block; width: 0.7rem; height: 0.7rem; border-radius: var(--tube-radius, 0); margin-right: 0.3em; vertical-align: -0.05em; border: var(--border); }
.sec__ramp { display: inline; }
.sec__ramp > b { margin: 0 0.35em; }
.sec__grad { display: inline-block; width: 4.5rem; height: 0.7rem; vertical-align: -0.05em; border: var(--border); border-radius: var(--radius-cap); }
/* the tasks, crew by crew: a chip is a wash of its crew's pale at rest, the crew's colour when it is the one shown */
.sec__tasks { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); }
.sec__crewrow { display: flex; align-items: flex-start; gap: var(--pad); }
.sec__crewname { flex: 0 0 6.5rem; padding-top: calc(var(--pad) / 2); font-weight: 500; line-height: 1.2; }
.sec__taskchips { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); min-width: 0; }
.sec__task { padding: calc(var(--pad) / 2) var(--pad); color: var(--v3-ink); background: var(--chip-light); border-color: var(--chip); box-shadow: none; }   /* (v20) the crew's own light shade, picked or not — its colour itself when picked */
.sec__task:hover { filter: brightness(1.06); }
.sec__task.is-selected, .sec__task[aria-pressed='true'] { background: var(--chip); color: var(--chip-ink); border: var(--border); border-color: var(--chip); outline: var(--selected-border); outline-offset: 0; }   /* (the same face picked or not: the chips beside it stay where they are) */
.sec__when { display: flex; flex-wrap: wrap; gap: var(--pad); }
.sec__field { flex: 1 1 8rem; flex-direction: column; align-items: stretch; gap: calc(var(--pad) / 4); }
.sec__field > .entry__date { width: 100%; }
/* (v50) the SER# box: always there (section.js v5) */
.sec__ser { text-transform: uppercase; }
.sec__done { font-weight: 700; min-height: calc(var(--t-label) * var(--lh) * 2 + 2 * var(--pad) + 0.125rem); }   /* (34.7: two lines' room — what it says grows with the task and the SER#, and the line and buttons under it never move) */
.sec__why { margin: 0; line-height: var(--lh); min-height: calc(var(--t-small) * var(--lh) * 3); }   /* (three lines' room — 34.7, a SER# for a task the tracker has no column for says so: the buttons under it stay where they are as it changes) */
.sec__acts { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); }
/* the section's progress, task by task: the tracker's share pale, what was entered on the site bright */
.sec__progress { display: flex; flex-direction: column; gap: var(--pad); }
.sec__proghead { display: flex; flex-wrap: wrap; align-items: baseline; gap: calc(var(--pad) / 2) var(--pad); }
.sec__proghead > h3 { margin: 0; font-size: var(--t-label); }
.sec__pgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr)); gap: calc(var(--pad) / 3) var(--gap); }
.sec__prow { display: flex; align-items: center; gap: var(--pad); min-width: 0; }
.sec__pname { flex: 0 0 7.5rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sec__pbar { flex: 1 1 auto; display: flex; height: 0.5rem; background: var(--raised); border-radius: var(--tube-radius); overflow: hidden; }
.sec__psheet { background: var(--chip-light); }
.sec__pmine { background: var(--chip); }
.sec__pnum { flex: 0 0 4rem; text-align: right; white-space: nowrap; }

/* ---------- (v25) AN LBD OR AN INVERTER, OPEN — ITS CIRCUITS AND ITS TERMINATIONS (lbdview.js) ----------
   It stands where the map was, as a section does (the map is under it, not shown). Nothing in it is a card: the panel
   is the card. The header — Up · the place · Drawing, and one line of what the place is — stays put while the rest
   scrolls under it, and is one height whatever is picked. Each switch (or inverter input) is a column: its name, the
   strings it takes, and a cell for each of the tab's four tasks — the day and the initials in the crew's colour when it
   is done (lbdview.js wears the crew: --crew-face / --crew-ink / --crew-soft). */
.entry__view .atlas[data-circuit] .context > .map { display: none; }
/* (v30 — Pete, 2026-10-16: "The buttons are cut off in the viewport window. At the top"): THE OPEN LBD OR INVERTER IS
   ITS BOX'S HEIGHT AND THE PAGE IS NEVER SCROLLED UNDER ANYTHING. The whole view scrolled, its header stuck over it, and
   the book page's own Zoom out · Zoom in · Fit · Open and the top of the page went under that header half way, cut.
   Now the header stands over the view and does not scroll; under it, on a wide view, the page takes the left column's
   whole height (its line and the tools under it) and the entry scrolls in its own column, so nothing scrolls at all
   on a desk; on a narrow view (a phone) the page's place stands at the TOP of what scrolls (sticky, nothing over it),
   as tall as the page's own shape at that width, and the key, the tools, the tasks, Completed and the progress scroll
   up UNDER it — the page, its buttons and its words never cut. */
.entry__view .atlas[data-circuit] .context > .lbd { flex: 1 1 auto; min-height: 0; overflow: hidden; container: lbd / size; }
.lbd { display: flex; flex-direction: column; gap: var(--gap); width: 100%; min-width: 0; --lbd-col: 3.4rem; --lbd-cell: 2.35rem; --lbd-radius: calc(var(--lbd-cell) * var(--radius-percent) / 100 * 0.5); }
.lbd__head { position: relative; flex: 0 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); padding-bottom: calc(var(--pad) / 2); }
.lbd__head > .lbd__up, .lbd__drawrow > .btn { width: auto; flex: 0 0 auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); white-space: nowrap; }
.lbd__title { margin: 0; font-size: var(--t-label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1 1 auto; }
.lbd__drawrow { display: flex; align-items: center; gap: calc(var(--pad) / 2); min-width: 0; flex: 0 1 auto; }
.lbd__drawwhy { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; max-width: 16rem; }
.lbd__about { flex: 1 0 100%; margin: 0; line-height: var(--lh); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-transform: none; }
/* (v66) with its Up in the bar (Layout 2), the open LBD's or PCS's name and Drawing share ONE line — the line Up gave up, so
   the page's place and Completed keep the room they had on a phone; what Drawing says shortens with … before it could wrap */
.atlas[data-upbar] .lbd__title { flex: 0 1 auto; }
.atlas[data-upbar] .lbd__drawrow { flex: 1 1 0; }
.lbd__body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: var(--gap); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
.lbd__left { display: contents; }   /* (narrow: the page's place, its line and the tools are the body's own — the place sticks over all of it) */
.lbd__entry { min-width: 0; display: flex; flex-direction: column; gap: var(--pad); }
/* wide: two columns, the page's place filling the left one, the entry scrolling in its own */
@container lbd (min-width: 46rem) {
  .lbd__body { flex-direction: row; align-items: stretch; overflow-y: hidden; }
  .lbd__left { display: flex; flex: 2 1 26rem; min-width: 0; min-height: 0; flex-direction: column; gap: var(--pad); }
  .lbd__entry { flex: 1 1 18rem; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
}
@container lbd (min-width: 46rem) and (max-height: 30rem) { .lbd__body { overflow-y: auto; } }   /* (a window too short for the page's place: the body scrolls, as a last resort) */
.lbd__grid { display: flex; flex-direction: column; gap: var(--pad); min-width: 0; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  /* (v30) one height whatever is in it — the book's page, or the line and the stand-in. Narrow: the page's own shape at
     this width (the book's sheets are 17 × 11) with its line over it, never more than three fifths of the view, standing
     at the top of what scrolls with nothing over it; wide: the left column's whole height */
  flex: 0 0 auto; height: min(calc(100cqw * 11 / 17 + 3.25rem), 60cqh); min-height: 14rem;
  position: sticky; top: 0; z-index: 4; background: var(--panel); box-shadow: 0 var(--pad) 0 0 var(--panel); }
@container lbd (min-width: 46rem) { .lbd__grid { position: relative; flex: 1 1 auto; height: auto; min-height: 18rem; box-shadow: none; } }
.lbd__grid > .lbddraw { flex: 1 1 auto; min-height: 0; max-height: none; }
.lbd__booknote { flex: 0 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); min-height: 2.4rem; margin: 0; text-transform: none; }
.lbd__booknote > .btn { width: auto; padding: calc(var(--pad) / 2) var(--pad); }
.lbd__booknote > .t-small { flex: 1 1 14rem; min-width: 0; }
.lbd__bookwait { flex: 1 1 auto; min-height: 0; }
/* (v27) THE BOOK'S DRAWINGS (lbddraw.js v2 — Pete, 2026-10-15: "Here is the underground, the inverter layout and the LBD
   layout" · "I want the drawings as the maps"): an open LBD is the DC Underground book's LBD layout, an open inverter its
   inverter layout — in the book's own colours (--ug-*); the words, the lines and the ground are the page's, so either
   mode reads. Each circuit one thing to tap; picked, a ring — never a heavier line — so the drawing never moves. */
.lbddraw { display: block; width: 100%; height: auto; max-height: 80vh; overflow: visible; font-family: inherit;
  --ug-ink: var(--text); --ug-words: color-mix(in oklab, var(--ug-label) 40%, var(--text)); }
@media (prefers-color-scheme: light) { :root:not([data-mode='dark']) .lbddraw { --ug-ink: var(--ug-navy); --ug-words: var(--ug-label); } }
:root[data-mode='light'] .lbddraw { --ug-ink: var(--ug-navy); --ug-words: var(--ug-label); }
.lbddraw--lbd { max-width: 30rem; }
.lbddraw--pcs { max-width: 48rem; }
/* the LBD layout */
.lbddraw__title { fill: var(--text); font-size: 13px; font-weight: 700; font-style: italic; }
.lbddraw__encl { fill: var(--card); stroke: var(--ug-ink); stroke-width: 1.4; }
.lbddraw__band { fill: var(--ug-band); stroke: var(--ug-ink); stroke-width: 1.4; }
.lbddraw__band-text { fill: var(--tab-paper); font-size: 11px; font-weight: 500; }
.lbddraw__place { fill: var(--card); stroke: var(--ug-ink); stroke-width: 1.2; }
.lbddraw__disc { fill: var(--ug-switch); stroke: var(--ug-ink); stroke-width: 1.2; }
.lbddraw__disc-letter { fill: var(--tab-paper); font-size: 12px; font-weight: 500; pointer-events: none; }
.lbddraw__gbar { fill: var(--ug-ground); stroke: var(--ug-ink); stroke-width: 1; }
.lbddraw__ground { fill: none; stroke: var(--ug-ground); stroke-width: 2.4; stroke-linecap: round; }
.lbddraw__pipe { fill: var(--ug-pipe); stroke: var(--ug-ink); stroke-width: 1.2; }
.lbddraw__pipe--one { fill: var(--ug-pipe-one); }
.lbddraw__wire { fill: none; stroke-width: 2.6; stroke-linecap: round; }
.lbddraw__wire--a { stroke: var(--ug-wire-a); }
.lbddraw__wire--b { stroke: var(--ug-wire-b); }
.lbddraw__wirehit { fill: none; stroke: transparent; stroke-width: 10; }
.lbddraw__dischit { fill: transparent; stroke: none; }
.lbddraw__side { fill: var(--text); font-size: 11px; font-weight: 700; }
.lbddraw__label-box { fill: var(--card); stroke: var(--ug-ink); stroke-width: 1; }
.lbddraw__arrow { fill: none; stroke: var(--ug-ink); stroke-width: 1; }
.lbddraw__wire-name { fill: var(--ug-words); font-size: 10px; font-weight: 700; }
.lbddraw__wire-name--list { font-size: 11px; }
.lbddraw__strings { fill: var(--text2); font-size: 8.5px; font-weight: 500; }
.lbddraw__state { fill: var(--text2); font-size: 9px; font-weight: 500; }
.lbddraw__state--small { font-size: 7.5px; }
.lbddraw__note { fill: var(--text2); font-size: 8.5px; font-weight: 500; }
.lbddraw__pip { fill: var(--raised); stroke: var(--text2); stroke-width: 0.5; }
/* the inverter layout */
.lbddraw__legend { fill: var(--card); stroke: var(--ug-ink); stroke-width: 1; }
.lbddraw__window-name { fill: var(--text); font-size: 10.5px; font-weight: 700; }
.lbddraw__spot { fill: var(--text2); font-size: 9px; font-style: italic; }
.lbddraw--pcs .lbddraw__wire-name { font-size: 8.2px; }
.lbddraw--pcs .lbddraw__wire-name--list { font-size: 9.6px; }
.lbddraw__rack { fill: var(--ug-rack); }
.lbddraw__rail { fill: var(--ug-rail); }
.lbddraw__window { fill: none; stroke: var(--ug-window); stroke-width: 2; }
.lbddraw__window-letter-box { fill: var(--card); stroke: var(--ug-ink); stroke-width: 1; }
.lbddraw__window-letter { fill: var(--text); font-size: 11px; font-weight: 700; }
.lbddraw__conduit { fill: none; stroke: var(--ug-conduit); stroke-width: 7; stroke-linejoin: round; }
.lbddraw__conduit--extra { stroke-dasharray: 4 3; }
.lbddraw__pvc { fill: var(--ug-pvc); stroke: var(--card); stroke-width: 1.2; }
.lbddraw__pvc--extra { fill: var(--card); stroke: var(--ug-pvc); stroke-dasharray: 2 1.5; }
.lbddraw__pvc-text { fill: var(--tab-paper); font-size: 6px; font-weight: 700; pointer-events: none; }
.lbddraw__pvc--extra + .lbddraw__pvc-text { fill: var(--text2); }
.lbddraw__label-box--extra { stroke-dasharray: 3 2; }
.lbddraw__wire-name--extra { fill: var(--text2); font-style: italic; font-weight: 500; }
/* done: the crew's colour — pale for the tracker's day, bright for one entered here (lbdview wears the crew) */
.lbddraw__row { fill: transparent; }
.lbddraw__row.is-done, .lbddraw__pip.is-done, .lbddraw__disc.is-done { fill: var(--crew-soft); }
.lbddraw__row.is-mine, .lbddraw__pip.is-mine, .lbddraw__disc.is-mine { fill: var(--crew-face); }
.lbddraw__pip.is-done, .lbddraw__pip.is-mine, .lbddraw__disc.is-done, .lbddraw__disc.is-mine { stroke: var(--crew-face); }
.lbddraw__wire-name.is-done, .lbddraw__state.is-done, .lbddraw__disc-letter.is-done { fill: var(--crew-soft-ink); }
.lbddraw__wire-name.is-mine, .lbddraw__state.is-mine, .lbddraw__disc-letter.is-mine { fill: var(--crew-ink); }
/* tapping: the circuit's whole <g>; picked, a ring round its line, its disc and its names */
.lbddraw__sw { cursor: pointer; outline: none; }
.lbddraw__sw:hover .lbddraw__row:not(.is-done):not(.is-mine), .lbddraw__sw:focus-visible .lbddraw__row:not(.is-done):not(.is-mine) { fill: color-mix(in oklab, var(--text) 8%, transparent); }
.lbddraw__sw.is-selected .lbddraw__row { stroke: var(--text); stroke-width: 1.4; }
.lbddraw__sw.is-selected .lbddraw__row:not(.is-done):not(.is-mine) { fill: color-mix(in oklab, var(--crew-face) 22%, transparent); }
.lbddraw__sw.is-selected .lbddraw__dischit { stroke: var(--text); stroke-width: 1.6; }
.lbd__key { margin: 0; line-height: var(--lh); min-height: calc(var(--t-small) * var(--lh) * 2); text-transform: none; }   /* (two lines' room: the buttons under it never move as it changes) */
.lbd__tools { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); }
.lbd__tools > .btn, .lbd__acts > .btn { width: auto; padding: calc(var(--pad) / 2) var(--pad); }
.lbd__readout { font-weight: 500; flex: 1 1 auto; min-width: 0; }
.lbd__tasks { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); }
.lbd__task { width: auto; padding: calc(var(--pad) / 2) var(--pad); text-transform: none; background: var(--crew-soft); color: var(--crew-soft-ink); border-color: var(--crew-face); box-shadow: none; }   /* the crew's light shade, picked or not — its colour itself when picked */
.lbd__task.is-selected, .lbd__task[aria-pressed='true'] { background: var(--crew-face); color: var(--crew-ink); border-color: var(--crew-face); outline: var(--selected-border); outline-offset: 0; }
.lbd__when { display: flex; flex-wrap: wrap; gap: var(--pad); }
.lbd__field { flex: 1 1 6rem; flex-direction: column; align-items: stretch; gap: calc(var(--pad) / 4); }
.lbd__field > .entry__date { width: 100%; }
.lbd__field.is-quiet { opacity: 0.55; }
.lbd__done { width: auto; font-weight: 700; }
.lbd__why { margin: 0; line-height: var(--lh); min-height: calc(var(--t-small) * var(--lh) * 2); }   /* (two lines' room: the buttons under it stay where they are as it changes) */
.lbd__acts { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); }
.lbd__progress { display: flex; flex-direction: column; gap: var(--pad); }
.lbd__proghead { display: flex; flex-wrap: wrap; align-items: baseline; gap: calc(var(--pad) / 2) var(--pad); }
.lbd__proghead > h3 { margin: 0; font-size: var(--t-label); }
.lbd__pgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr)); gap: calc(var(--pad) / 3) var(--gap); }
.lbd__prow { display: flex; align-items: center; gap: var(--pad); min-width: 0; }
.lbd__pname { flex: 0 0 9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lbd__pbar { flex: 1 1 auto; display: flex; height: 0.5rem; background: var(--raised); border-radius: var(--lbd-radius); overflow: hidden; }
.lbd__psheet { background: var(--crew-soft); }
.lbd__pmine { background: var(--crew-face); }
.lbd__pnum { flex: 0 0 4rem; text-align: right; white-space: nowrap; }

/* ---------- THE BLOCKS · CREW % TABLE (V3's, beside its map — here the List face of the map view: Draw | List, above) ----------
   A cell is its crew's colour by the block's share; a tap goes to that crew's next section in the block. */
.blocktable { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); width: 100%; min-width: 0; }
.blocktable:empty { display: none; }
.blocktable > h3 { margin: 0; font-size: var(--t-label); }
.blocktable > p { margin: 0; }
.blocktable__grid { display: grid; grid-template-columns: minmax(1.6em, auto) repeat(6, minmax(0, 1fr)) minmax(0, 1.15fr); gap: 0.125rem; align-items: stretch; font-size: var(--t-small); }
.blocktable__h { font-size: calc(var(--t-small) * 0.8); font-weight: 500; letter-spacing: 0.03em; text-transform: uppercase; text-align: center; color: var(--text2); padding-bottom: 0.125rem; }
.blocktable__h:first-child { text-align: left; }
.blocktable__h.is-selected { color: var(--text); font-weight: 700; text-decoration: underline; }
.blocktable__b { font-weight: 700; align-self: center; }
.blocktable__cell { appearance: none; -webkit-appearance: none; font: inherit; font-weight: 500; text-align: center; padding: 0.2em 0; margin: 0; min-width: 0; cursor: pointer; border: 0; background: color-mix(in oklab, var(--chip) var(--a), transparent); }
.blocktable__cell:hover, .blocktable__cell:focus-visible { outline: var(--selected-border); outline-offset: 0; }
.blocktable__mod { margin-left: 0.3rem; }   /* the modules stand apart from the racking crews, as V3 ruled them off */
.crewgrid { display: grid; grid-template-columns: repeat(var(--n, 5), minmax(0, 1fr)); gap: var(--pad); width: 100%; }
.crewgrid > .btn { width: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.entry__top { width: 100%; flex: 0 0 auto; }
.entry__toggle { width: auto; align-self: flex-start; }
.side__main { display: flex; flex-direction: column; gap: var(--gap); }
/* the home screen's crews: a row of buttons above the tasks (Pete, 2026-09-26); the crew you
   picked is marked, and its tasks are what is listed under it */
.crews { display: flex; flex-wrap: wrap; gap: var(--pad); }
.crews > .btn { width: auto; flex: 1 1 auto; }

/* the status row's data light — one of three, one at a time. It is LIT (Pete, 2026-09-26:
   "shine like an actual light"): the same bright colour in both modes, a highlight on the
   bulb, and its own colour cast on the ground around it. The glow is drawn outside the box
   and moves nothing. */
.dot { --light: var(--light-amber); display: inline-block; width: 0.8em; height: 0.8em; border-radius: 50%; margin-right: 0.4em; vertical-align: -0.08em;
  background: radial-gradient(circle at 35% 32%, oklch(var(--light-highlight-l) 0.04 100) 0, var(--light) 55%, var(--light) 100%);
  box-shadow: 0 0 var(--light-glow-size) color-mix(in oklch, var(--light) calc(var(--light-glow-alpha) * 100%), transparent), 0 0 calc(var(--light-glow-size) * 2.2) color-mix(in oklch, var(--light) calc(var(--light-glow-alpha) * 45%), transparent); }
.dot--green { --light: var(--light-green); }
.dot--amber { --light: var(--light-amber); }
.dot--red { --light: var(--light-red); }
/* a bulb that has not been checked yet: unlit, no glow (the header's lights before the first Health Check) */
.dot--off { background: var(--raised); border: var(--border); box-shadow: none; }
/* A RAINBOW (Pete, 2026-09-26: "I don't like seeing the same colour everywhere"): buttons in a
   .rainbow group take the row hues in turn, so five buttons are five colours. */
.rainbow > .btn:nth-of-type(6n + 1), .rainbow > a.btn:nth-of-type(6n + 1) { --bl: var(--btn-tools-l); --bc: var(--btn-tools-c); --bh: var(--btn-tools-h); }
.rainbow > .btn:nth-of-type(6n + 2), .rainbow > a.btn:nth-of-type(6n + 2) { --bl: var(--btn-banner-l); --bc: var(--btn-banner-c); --bh: var(--btn-banner-h); }
.rainbow > .btn:nth-of-type(6n + 3), .rainbow > a.btn:nth-of-type(6n + 3) { --bl: var(--btn-filters-l); --bc: var(--btn-filters-c); --bh: var(--btn-filters-h); }
.rainbow > .btn:nth-of-type(6n + 4), .rainbow > a.btn:nth-of-type(6n + 4) { --bl: var(--btn-status-l); --bc: var(--btn-status-c); --bh: var(--btn-status-h); }
.rainbow > .btn:nth-of-type(6n + 5), .rainbow > a.btn:nth-of-type(6n + 5) { --bl: var(--btn-digitools-l); --bc: var(--btn-digitools-c); --bh: var(--btn-digitools-h); }
.rainbow > .btn:nth-of-type(6n + 6), .rainbow > a.btn:nth-of-type(6n + 6) { --bl: var(--btn-dialogue-l); --bc: var(--btn-dialogue-c); --bh: var(--btn-dialogue-h); }
/* the zoom controls sit in each block's header line, between its name and its tally */
.viewer__controls { display: inline-flex; align-items: center; gap: calc(var(--pad) / 2); flex: 0 0 auto; }
.viewer__controls > .btn { width: auto; font-size: var(--t-small); padding: var(--pad); }
.viewer__zoom { font-size: var(--t-small); font-weight: 700; min-width: 4ch; text-align: center; font-variant-numeric: tabular-nums; }
.viewer__box .row-between { flex-wrap: wrap; }
/* No scrollbar-color/scrollbar-width here on purpose: setting them makes Chrome ignore the
   ::-webkit-scrollbar rules below, and those are what force a scrollbar that is ALWAYS drawn —
   on a Mac too, where the system's own would hide until touched. Firefox draws its own. */
.viewer__box { display: flex; flex-direction: column; gap: var(--gap); overflow: auto; height: 75vh; padding: var(--pad); background: var(--panel); border: var(--border); border-radius: var(--radius-cap); scrollbar-gutter: stable; }
.viewer__box::-webkit-scrollbar { width: 1em; height: 1em; }
.viewer__box::-webkit-scrollbar-track { background: var(--card); border-radius: 1em; }
.viewer__box::-webkit-scrollbar-thumb { background: var(--text2); border-radius: 1em; border: 0.15em solid var(--card); }
.viewer__box::-webkit-scrollbar-corner { background: var(--card); }
.viewer__box > * { flex: 0 0 auto; }
.form-fit { flex: 0 0 auto; }
@media (min-width: 60rem) {
  .side { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); align-items: start; }
  .side__main { order: 1; position: sticky; top: calc(var(--strip-height, 0px) + var(--gap)); height: calc(100vh - var(--strip-height, 0px) - var(--gap) * 2); min-width: 0; }   /* task.js sets the height to the room that is actually there */
  .side__main > .viewer, .side__main > .mapview { flex: 1 1 auto; min-height: 0; height: auto; }
  .side__main .viewer__box { flex: 1 1 auto; min-height: 0; height: auto; }
  /* the column pins to the top beside the viewer and scrolls inside itself when it is taller
     than the screen (task.js sets its height, like the viewer's) */
  .side__aside { order: 2; position: sticky; top: calc(var(--strip-height, 0px) + var(--gap)); overflow: auto; scrollbar-gutter: stable; }
  .side__aside::-webkit-scrollbar { width: 0.8em; }
  .side__aside::-webkit-scrollbar-track { background: var(--card); border-radius: 1em; }
  .side__aside::-webkit-scrollbar-thumb { background: var(--text2); border-radius: 1em; border: 0.15em solid var(--card); }
}

/* Rows the person has hidden from the Rows control on the status row (rows.js). The status row
   itself is not in this list and must never be added to it: it is where they come back. The
   strip re-measures itself, so the page keeps its reserve and nothing under it moves. */
/* the view row belongs to the map: a page without the site map has no row (filters.js) */
:root[data-filters-page='off'] [data-row='filters'] { display: none; }
:root[data-hide-banner='true'] [data-row='banner'],
:root[data-hide-tools='true'] [data-row='tools'],
:root[data-hide-filters='true'] [data-row='filters'],
:root[data-hide-dialogue='true'] [data-row='dialogue'] { display: none; }
.rowsctl { display: flex; flex: 0 0 auto; gap: calc(var(--pad) / 2); }   /* keeps its width in the status row; the readouts to its right are what get clipped */
/* each Hide/Show button wears the colour of the row it controls; Full screen wears its own row's */
/* (wherever the control lives — the status row in Layout 1, the left drawer in Layout 2) */
.rowsctl .rows__btn--banner   { --bl: var(--btn-banner-l);   --bc: var(--btn-banner-c);   --bh: var(--btn-banner-h); }
.rowsctl .rows__btn--tools    { --bl: var(--btn-tools-l);    --bc: var(--btn-tools-c);    --bh: var(--btn-tools-h); }
.rowsctl .rows__btn--dialogue { --bl: var(--btn-dialogue-l); --bc: var(--btn-dialogue-c); --bh: var(--btn-dialogue-h); }
.rowsctl .rows__btn--filters  { --bl: var(--btn-filters-l);  --bc: var(--btn-filters-c);  --bh: var(--btn-filters-h); }
.rowsctl .rows__btn--status   { --bl: var(--btn-status-l);   --bc: var(--btn-status-c);   --bh: var(--btn-status-h); }
.rowsctl > .btn { font-size: var(--t-small); padding: var(--pad); flex: 0 0 auto; width: auto; justify-content: center; white-space: nowrap; }   /* its own width — both labels stacked inside (.vals), so Hide → Show moves nothing */

/* ---------- task (task.js): the printed page, on screen ---------- */
.form-fit { width: 100%; overflow: hidden; }
.form-fit > .form-page { margin: 0; }

/* ---------- task (task.js) ---------- */
.rows { display: flex; flex-direction: column; gap: calc(var(--pad) / 3); }
.rowline { display: grid; grid-template-columns: 6rem 1fr 6rem 6rem; gap: var(--pad); align-items: center; padding: var(--pad); background: var(--raised); font-size: var(--t-body); font-variant-numeric: tabular-nums; }
.rowline--done { background: var(--card-selected); }
.rowline__date { font-weight: 700; }

/* the mind map: a grounded map — buildings anchored on the ground, roads under them */
.mind { position: relative; width: 100%; aspect-ratio: 3 / 2; background: var(--panel); border: var(--border); overflow: hidden; min-height: 24rem; }
.mind__roads { position: absolute; inset: 0; width: 100%; height: 100%; }
.mind__road { stroke: var(--text2); stroke-linecap: round; opacity: 0.7; }
.mind__building { position: absolute; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 0.1em; padding: var(--pad); background: var(--card); border: var(--border); color: var(--text); text-decoration: none; overflow: hidden; min-width: 0; }
.mind__building:hover { background: var(--card-hover); }
.mind__building--site { background: var(--raised); border: var(--selected-border); }
.mind__building--cloud { border-style: dashed; }
.mind__building--service { background: var(--bg); }
.mind__ink { position: absolute; inset: 8%; background: var(--text2); opacity: 0.5; -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; pointer-events: none; }
.mind__name { position: relative; font-weight: 700; font-size: var(--t-label); line-height: 1.1; overflow-wrap: anywhere; }
.mind__what { position: relative; line-height: 1.15; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.mind__use { position: relative; }
@media (max-width: 45rem) { .mind { aspect-ratio: 2 / 3; } .mind__what { display: none; } .mind__name { font-size: var(--t-small); } }

/* Night Vision: the day's assignment line */
.nv__today { font-weight: 700; }
.nv select[multiple] { height: auto; }

/* an RFI */
.rfi--answered { opacity: 0.85; }

/* the Inbox: conversations on the left, the thread on the right (one column on a phone) */
/* THE INBOX, LIKE GMAIL (inbox.js v4, Pete 2026-09-27): the categories down the left, the messages
   on the right, newest first; a row is bold until it has been opened */
.mail { display: grid; grid-template-columns: 1fr; gap: var(--gap); width: 100%; min-width: 0; }
.mail > * { min-width: 0; }
@media (min-width: 60rem) { .mail { grid-template-columns: minmax(11rem, 1fr) minmax(0, 4fr); align-items: start; } }
.mail__nav > .btn { width: 100%; display: flex; justify-content: space-between; align-items: center; gap: var(--pad); text-align: left; }
.mail__cat-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mail__count { flex: 0 0 auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.mail__list { display: flex; flex-direction: column; gap: calc(var(--pad) / 3); }
.mail__row { width: 100%; display: grid; grid-template-columns: minmax(7rem, 1fr) minmax(0, 4fr) auto; gap: var(--pad); align-items: center; text-align: left;
  font: inherit; font-size: var(--t-label); color: var(--text); background: var(--card); border: var(--border); padding: var(--pad); cursor: pointer; }
.mail__row > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mail__row:hover { background: var(--raised); }
.mail__row.is-unread { font-weight: 700; }
.mail__row.is-unread .mail__who::before { content: '● '; }
.mail__when { color: var(--text2); }
.mail__chips { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); }
.mail__chips > .btn { width: auto; }
.mail__newperson { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); align-items: center; }
.mail__in { position: static; flex: 1 1 12rem; height: 2.4em; font-size: var(--t-small); padding: 0 var(--pad); background: var(--raised); color: var(--text); border: var(--border); }
.mail__newperson > .btn { width: auto; flex: 0 0 auto; }
.inbox__msg--mine { background: var(--card-selected); }
.inbox__text { white-space: pre-wrap; overflow-wrap: anywhere; }

/* the presentation stage: the document as big as the panel, or the screen */
.present__media { display: block; width: 100%; max-height: 80vh; object-fit: contain; background: var(--bg); }
.present__media--pdf { height: 80vh; border: 0; }
.present:fullscreen { background: var(--bg); padding: var(--pad); display: flex; flex-direction: column; }
.present:fullscreen .present__media { flex: 1 1 auto; max-height: none; height: auto; min-height: 0; }
.present:fullscreen .present__media--pdf { height: 100%; }

/* the leaderboard: a bar per crew in the crew's colour */
.lb__bar { width: 100%; height: 0.9em; background: var(--raised); border: var(--border); overflow: hidden; }
.lb__fill { display: block; height: 100%; background: var(--lb-fill, var(--text2)); }

/* a document's card */
.doc h4 { overflow-wrap: anywhere; }
.doc__revs { border-top: var(--border); padding-top: var(--pad); }

/* ---------- the Document Control Center: Shared With Vantage (documents.js v3) ---------- */
/* the address a Drive file is shared with, and the link row under it: a label, a box that takes the room, a button */
.share-as { display: flex; flex-wrap: wrap; align-items: center; gap: var(--pad); }
.share-as > label, .share-as__label { flex: 0 0 auto; white-space: nowrap; }
.share-as > .btn { width: auto; flex: 0 0 auto; }
.share-as__box { flex: 1 1 12rem; min-width: 0; }
/* the address itself: the whole of it at any width, wrapped rather than cut, and selected whole on a tap */
.share-as__address {
  font-size: var(--t-label); line-height: var(--lh);
  color: var(--dialogue-ink); background: var(--dialogue-fill); border: var(--border); padding: var(--pad);
  overflow-wrap: anywhere; user-select: all; cursor: text;
}
.share-as__address[data-known='false'] { color: color-mix(in oklch, var(--dialogue-ink) 70%, transparent); user-select: none; }
.share-as__address:focus-visible { outline: var(--selected-border); outline-offset: calc(var(--pad) / 4); }
/* the selector: a box of its own that scrolls, the same height from the moment it opens, so nothing under it moves */
.gpick__box { height: var(--gpick-height); }
.gpick > .row-between { align-items: center; }
.gpick__said { flex: 1 1 auto; min-width: 0; }
/* on a narrow screen the line under the list wraps: its room is kept, so the answer arriving moves nothing below */
@media (max-width: 45rem) { .gpick__said { min-height: calc(var(--lh) * 3em); } }
.gpick > .row-between > .choice { flex: 0 0 auto; flex-wrap: nowrap; }
.file-tile[aria-pressed='true'] .file-tile__meta { color: var(--text); }
/* a Drive file's card: the light in its name line; what Vantage found; the one thing to do */
.gdocs { --unit: var(--gdoc-unit); }
/* its name is the FILE'S OWN, to the letter — it is how the person finds it in Drive, and the selector's tile above
   shows the same: "Racking install — block 7.mp4" is not retitled "….Mp4" (the Proper Case rule is for the site's own titles) */
.gdoc h4 { display: flex; align-items: baseline; gap: calc(var(--pad) / 2); min-width: 0; text-transform: none; }
.gdoc h4 > .dot { flex: 0 0 auto; margin-right: 0; }
.gdoc__state, .gdoc__detail { overflow-wrap: anywhere; }
.gdoc > .choice { margin-top: auto; }   /* the buttons sit at the foot, so a row of cards lines up */
/* (v31 — Pete, 2026-10-17: "I want to be able to see the files that are in the folder, from Vantage") A DRIVE FOLDER'S
   CARD takes the row's whole width and shows what is in it: a line a file or folder — its own name to the letter, what
   it is, when it changed and by whom, its size, Open — a folder in it opening in place under its line, indented. The
   list stands in a box of one height that scrolls, so nothing below it moves when the answer comes or a folder opens. */
.gdoc--folder { grid-column: 1 / -1; }
.gfolder { gap: calc(var(--pad) / 2); min-width: 0; }
.gfolder__count { margin: 0; }
.gfolder__box { height: clamp(10rem, 45vh, 26rem); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: calc(var(--pad) / 3); padding: calc(var(--pad) / 2); border: var(--border); background: var(--panel); }
.gfolder__line { flex: 0 0 auto; display: flex; align-items: center; gap: var(--pad); min-width: 0; min-height: 2.25rem; padding-left: calc(var(--depth, 0) * 1.25rem); }
.gfolder__line.skeleton { min-height: 2.25rem; }
.gfolder__open, .gfolder__file { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 0.4em; font: inherit; font-size: var(--t-label); color: var(--text); background: none; border: 0; padding: 0; text-align: left; }
.gfolder__open { cursor: pointer; font-weight: 500; }
.gfolder__caret { flex: 0 0 auto; width: 1em; }
.gfolder__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-transform: none; }
.gfolder__meta { flex: 0 1 auto; min-width: 0; max-width: 45%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gfolder__line > .btn { flex: 0 0 auto; width: auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); }
.gfolder__said { margin: 0; padding-left: calc(var(--depth, 0) * 1.25rem); }
/* a phone: the name and Open on one line, what it is under the name — Open never pushed onto a line of its own */
@media (max-width: 45rem) {
  .gfolder__line { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--pad); row-gap: 0; }
  .gfolder__line > .gfolder__open, .gfolder__line > .gfolder__file { grid-column: 1; grid-row: 1; }
  .gfolder__line > .btn { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  .gfolder__line > .btn:only-child { grid-column: 1; grid-row: 1; justify-self: start; }
  .gfolder__meta { grid-column: 1; grid-row: 2; max-width: none; }
}
/* (v32) a Google Sheet's line in a folder: View and Edit together, where Open is on any other line */
.gfolder__acts { flex: 0 0 auto; display: flex; gap: calc(var(--pad) / 2); }
.gfolder__acts > .btn { flex: 0 0 auto; width: auto; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); }
@media (max-width: 45rem) { .gfolder__line > .gfolder__acts { grid-column: 2; grid-row: 1 / span 2; align-self: center; } }

/* (v32) A GOOGLE SHEET, SEEN (gsheet.js — Pete, 2026-10-17: "Let's just add a viewer, and if somebody wants to edit there's
   an edit button that opens it in Google Sheets"). The head is one height whatever the sheet: its name on one line, the
   tabs on one line that scrolls sideways, what is showing on a line of two lines' room. The grid's box is one height and
   scrolls both ways; the sheet stands on its own paper in either mode (it is the person's document, as the book's pages
   are), its looks the inline rules gsheet.js writes from the sheet — fill, ink, weight, size in the sheet's points,
   alignment, wrap, borders — in OKLCH, in Roboto. The column letters and the row numbers stay put, and so do the sheet's
   own frozen rows and columns. Widths and heights are the sheet's own pixels, made rem. */
.gsheet { --gs-pt: calc(1rem / 12); --gs-num: 2.875rem; --gs-head: 1.25rem;
  --gs-chrome: color-mix(in oklch, var(--sheet-paper) 95%, var(--sheet-ink)); --gs-chrome-ink: color-mix(in oklch, var(--sheet-paper) 40%, var(--sheet-ink)); }
.gsheet__head { gap: calc(var(--pad) / 2); min-width: 0; }
.gsheet__top { gap: var(--pad); flex-wrap: wrap; }   /* (on a phone Edit goes under Back — both whole, never cut) */
.gsheet__top > .btn { flex: 0 0 auto; white-space: nowrap; }
.gsheet__name { margin: 0; text-transform: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }   /* the sheet's own name, to the letter */
.gsheet__tabs { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: thin; padding-bottom: 0.25rem; min-height: calc(var(--t-label) * var(--lh) + 2 * var(--pad) + 0.5rem); }
.gsheet__tabs > .gsheet__tab { flex: 0 0 auto; width: auto; min-width: 6rem; white-space: nowrap; text-transform: none; box-shadow: inset 0 -0.25rem 0 var(--gs-tab, transparent), var(--glow); }
.gsheet__tabs > .gsheet__tab[aria-pressed='true'] { border: var(--border); outline: var(--selected-border); outline-offset: -0.15rem; }   /* (a ring, never a heavier border: the row never moves) */
.gsheet__status { display: flex; align-items: center; gap: var(--pad); min-width: 0; min-height: max(calc(var(--t-small) * var(--lh) * 2), calc(var(--t-label) * var(--lh) + 2 * var(--pad))); }
.gsheet__said { flex: 1 1 0; margin: 0; min-width: 0; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }   /* (two lines' room, never more: the box under it never moves) */
.gsheet__more { flex: 0 0 auto; width: auto; white-space: nowrap; }
/* a phone: what is showing on its own two lines, the next rows under it — room kept for the button when there are no more */
@media (max-width: 45rem) {
  .gsheet__status { flex-wrap: wrap; align-content: flex-start; row-gap: calc(var(--pad) / 2); min-height: calc(var(--t-small) * var(--lh) * 2 + var(--pad) / 2 + var(--t-label) * var(--lh) + 2 * var(--pad)); }
  .gsheet__said { flex: 1 1 100%; min-height: calc(var(--t-small) * var(--lh) * 2); }
}
.gsheet__box { position: relative; height: clamp(18rem, calc(100dvh - 18rem), 90rem); overflow: auto; overscroll-behavior: contain; background: var(--sheet-paper); border: var(--border); }
.gsheet__wait { width: 100%; height: 100%; }
.gsheet__none { margin: 0; padding: var(--pad); color: var(--sheet-ink); }
.gsheet__grid { border-collapse: separate; border-spacing: 0; table-layout: fixed; background: var(--sheet-paper); color: var(--sheet-ink); font-family: Roboto, sans-serif; font-size: calc(var(--gs-pt) * 10); line-height: 1.2; }
.gsheet__num { width: var(--gs-num); }
.gsheet__grid td { padding: 0 0.1875rem; overflow: hidden; white-space: nowrap; vertical-align: bottom; text-align: left; border-right: 0.0625rem solid var(--sheet-gridline); border-bottom: 0.0625rem solid var(--sheet-gridline); background-clip: padding-box; }
.gsheet__grid td.is-over { overflow: visible; }
.gsheet__grid td a { color: inherit; text-decoration: underline; }
.gsheet__grid th { font-family: Roboto, sans-serif; font-weight: 400; font-size: calc(var(--gs-pt) * 8); color: var(--gs-chrome-ink); background: var(--gs-chrome); border-right: 0.0625rem solid var(--sheet-gridline); border-bottom: 0.0625rem solid var(--sheet-gridline); padding: 0 0.125rem; text-align: center; vertical-align: middle; white-space: nowrap; overflow: hidden; text-transform: none; }
.gsheet__letters > th { position: sticky; top: 0; z-index: 3; height: var(--gs-head); }
.gsheet__rownum { position: sticky; left: 0; z-index: 2; }
.gsheet__letters > th.gsheet__corner { left: 0; z-index: 5; }
.gsheet__grid tr.is-frozen-row > td, .gsheet__grid tr.is-frozen-row > th { position: sticky; top: var(--gs-top); z-index: 2; }
.gsheet__grid tr.is-frozen-row > th { z-index: 4; }
.gsheet__grid td.is-frozen-col { position: sticky; z-index: 1; background-color: var(--sheet-paper); }
.gsheet__grid tr.is-frozen-row > td { background-color: var(--sheet-paper); }
.gsheet__grid tr.is-frozen-row > td.is-frozen-col { z-index: 3; }
.gsheet__letters > th.is-frozen-col { z-index: 4; }   /* (its left is inline: after the row numbers and the frozen columns before it) */
.gsheet__grid tr.is-frozen-row:has(+ tr:not(.is-frozen-row)) > * { border-bottom: 0.125rem solid var(--gs-chrome-ink); }   /* the line under the frozen rows, as the sheet draws it */

/* (v33) THE JOB'S FILES — one file system (documents.js v13, fs.js). Everything in it is one height whatever is chosen,
   found or filtered: the tools' lines, the bar for the chosen one, and the list's box, which scrolls on its own; its
   rows are drawn only in view, so the box's height is the rows' (--fs-row × how many). Names are to the letter. */
.fs { min-width: 0; }
.fs__wait { height: clamp(24rem, calc(100dvh - 12rem), 64rem); }
.fs__tools { gap: calc(var(--pad) / 2); min-width: 0; }
.fs__search { width: 100%; }
.fs__fields { display: flex; flex-wrap: wrap; align-items: flex-end; gap: calc(var(--pad) / 2) var(--pad); min-width: 0; }
.fs__field { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.fs__select { width: auto; max-width: 100%; field-sizing: content; }
.fs__dir { white-space: nowrap; }
.fs__chipline { display: flex; align-items: center; gap: var(--pad); min-width: 0; }
.fs__label { flex: 0 0 auto; }
.fs__chipline > .fs__label { min-width: 2.75rem; }
.fs__chips { flex: 1 1 0; display: flex; flex-wrap: nowrap; gap: calc(var(--pad) / 2); min-width: 0; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: thin; padding: 0.2rem 0.15rem; min-height: calc(var(--t-small) * var(--lh) + var(--pad) + 0.4rem); }
.fs__chips > .btn.fs__chip { flex: 0 0 auto; width: auto; white-space: nowrap; font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); }
.fs__chip[aria-pressed='true'] { border: var(--border); outline: var(--selected-border); outline-offset: -0.1rem; }   /* (a ring, never a heavier border: the line never moves) */
.fs__n { opacity: 0.75; font-variant-numeric: tabular-nums; }
.fs__saidline { display: flex; align-items: center; gap: var(--pad); min-width: 0; height: max(calc(var(--t-small) * var(--lh) * 2), calc(var(--t-label) * var(--lh) + 2 * var(--pad) + 0.125rem)); }   /* (one height, Clear there or not) */
.fs__said { flex: 1 1 0; margin: 0; min-width: 0; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
.fs__saidline > .btn { flex: 0 0 auto; width: auto; white-space: nowrap; }
.fs__act { display: flex; flex-direction: column; justify-content: center; gap: calc(var(--pad) / 2); min-width: 0; padding: calc(var(--pad) / 2) var(--pad); border: var(--border); background: var(--card); }
.fs__actline { margin: 0; min-height: calc(var(--t-small) * var(--lh) * 2); overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.fs__actname { text-transform: none; }
.fs__actbtns { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: thin; min-height: calc(var(--t-label) * var(--lh) + 2 * var(--pad) + 0.3rem); padding-bottom: 0.15rem; }
.fs__actbtns > .btn { flex: 0 0 auto; white-space: nowrap; }
.fs__work { min-width: 0; padding: var(--pad); border: var(--border); background: var(--card); }
.fs__revlist { max-height: 16rem; overflow: auto; display: flex; flex-direction: column; gap: calc(var(--pad) / 3); }
.fs__rev > .btn { flex: 0 0 auto; width: auto; }
.fs__list { container: fslist / inline-size; position: relative; height: clamp(22rem, calc(100dvh - 14rem), 72rem); overflow: auto; overscroll-behavior: contain; border: var(--border); background: var(--panel); }
.fs__list, .fs__body { --fs-row: 2.5rem; --fs-cols: minmax(0, 3fr) 4.25rem minmax(0, 2fr) 4.75rem 5.25rem minmax(0, 1fr); }
.fs__list.fs--tree, .fs--tree .fs__body { --fs-cols: minmax(0, 4fr) 4.25rem 0 4.75rem 5.25rem minmax(0, 1.25fr); }
.fs__cols { position: sticky; top: 0; z-index: 2; display: grid; grid-template-columns: var(--fs-cols); background: var(--panel); border-bottom: var(--border); }
.fs__col { font: inherit; font-size: var(--t-small); color: var(--text2); background: none; border: 0; text-align: left; padding: calc(var(--pad) / 2); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.fs__col[aria-sort='ascending']::after { content: ' ▲'; }
.fs__col[aria-sort='descending']::after { content: ' ▼'; }
.fs--tree .fs__col--where, .fs--tree .fs__where { visibility: hidden; padding: 0; }
.fs__body { position: relative; }
.fs__row { position: absolute; left: 0; right: 0; height: var(--fs-row); display: grid; grid-template-columns: var(--fs-cols); align-items: center; font: inherit; font-size: var(--t-small); color: var(--text); background: none; border: 0; border-bottom: 0.0625rem solid color-mix(in oklch, var(--text) 10%, transparent); text-align: left; padding: 0; margin: 0; cursor: pointer; }
.fs__row > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 calc(var(--pad) / 2); }
.fs__row > .fs__name { display: flex; align-items: center; gap: 0.35em; padding-left: calc(var(--pad) / 2 + var(--depth, 0) * 1.1rem); text-transform: none; }
.fs__row .dot { flex: 0 0 auto; margin-right: 0; }
.fs__caret { flex: 0 0 auto; width: 1em; color: var(--text2); }
.fs__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fs__row--folder .fs__text, .fs__row--group .fs__text { font-weight: 500; }
.fs__size, .fs__changed { font-variant-numeric: tabular-nums; }
.fs__kind, .fs__where, .fs__size, .fs__changed, .fs__by { color: var(--text2); }
.fs__row:hover { background: color-mix(in oklch, var(--card) 70%, transparent); }
.fs__row[aria-selected='true'] { background: var(--card-selected); outline: var(--selected-border); outline-offset: -0.15rem; }
.fs__row--note { cursor: default; color: var(--text2); font-style: italic; }
.fs__row--note:hover { background: none; }
/* a narrow list: two lines a row — its name, then what it is, its size, when it changed and where it is */
@container fslist (max-width: 40rem) {
  .fs__body { --fs-row: 3.4rem; }
  .fs__cols { display: none; }
  .fs__row { grid-template-columns: auto auto auto minmax(0, 1fr); grid-template-areas: 'name name name name' 'kind size changed where'; align-content: center; row-gap: 0.1rem; }
  .fs__row > .fs__name { grid-area: name; }
  .fs__row > .fs__kind { grid-area: kind; padding-left: calc(var(--pad) / 2 + var(--depth, 0) * 1.1rem + 1.35em); }
  .fs__row > .fs__size { grid-area: size; }
  .fs__row > .fs__changed { grid-area: changed; }
  .fs__row > .fs__where { grid-area: where; }
  .fs__row > .fs__by { display: none; }
  .fs__row > span:empty { padding: 0; }
}
/* (v33) MAKE A DOCUMENT FROM PAGES (pagepick.js): the pages small, in a box of one height that scrolls; a kept one ringed */
.pagepick { gap: calc(var(--pad) / 2); min-width: 0; }
.pagepick__head { margin: 0; }
.pagepick__said, .pagepick__done { margin: 0; min-height: calc(var(--t-small) * var(--lh) * 2); }
.pagepick__grid { height: clamp(14rem, 42vh, 30rem); overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; display: grid; grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); gap: var(--pad); align-content: start; padding: calc(var(--pad) / 2); border: var(--border); background: var(--panel); }
.pagepick__page { position: relative; display: flex; align-items: center; justify-content: center; aspect-ratio: var(--pp-aspect, 17 / 11); padding: 0; border: var(--border); background: var(--sheet-paper); cursor: pointer; overflow: hidden; }
.pagepick__page[aria-pressed='true'] { outline: var(--selected-border); outline-offset: 0.1rem; }
.pagepick__img { width: 100%; height: 100%; object-fit: contain; display: block; }
.pagepick__n { position: absolute; left: 0.25rem; bottom: 0.25rem; font-size: var(--t-small); padding: 0 0.3rem; background: var(--panel); color: var(--text); border-radius: 0.3rem; }
.pagepick__page[aria-pressed='true'] .pagepick__n { background: var(--card-selected); font-weight: 700; }
.pagepick__line { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); min-width: 0; }
.pagepick__line > .dialogue__input { flex: 1 1 12rem; min-width: 0; }
.pagepick__line > .btn { flex: 0 0 auto; width: auto; }
.pagepick__line > .pick { flex: 0 1 auto; width: auto; max-width: 100%; field-sizing: content; }
.pagepick__done { flex: 1 1 12rem; }

/* (v21) a file or sheet FROM AUTODESK: its name and its folder are Autodesk's own, to the letter ("E-050 · Site Plan",
   "Project Files / 03 Electrical") — the Proper Case rule is for the site's own titles */
.addoc h4, .addoc__folder { text-transform: none; overflow-wrap: anywhere; }
.addoc > .choice { margin-top: auto; }
.ad-pull h2 { display: flex; align-items: center; gap: calc(var(--pad) / 2); }
/* (v23) UPLOAD SHEETS: what each page of the PDF is, and what became of it */
.sheets__list { gap: calc(var(--pad) / 2); max-height: 50vh; overflow: auto; }
.sheetrow { gap: var(--pad); align-items: baseline; }
.sheetrow__text { min-width: 0; overflow-wrap: anywhere; }
.sheetrow__name { font-weight: 700; text-transform: none; }
.sheetrow__state { flex: 0 0 auto; white-space: nowrap; font-weight: 700; }
.sheetrow__state--kept { color: var(--text2); font-weight: 400; }
.sheetcard__areas { overflow-wrap: anywhere; }
/* (v22) a press for many differences at once waits for its second tap: the first marks the button and says so */
.btn.is-armed { outline: var(--selected-border); outline-offset: 0.15rem; }
.diffs__batch { gap: var(--pad); flex-wrap: wrap; }
.diffs__batch.muted .t-small { color: var(--text2); }

/* an integration's card: the light in its name line */
.intg h4 { display: flex; align-items: center; gap: calc(var(--pad) / 2); }
.intg .dialogue__input { flex: 1 1 14rem; }


/* ============================================================================
   LAYOUT 2 — THE DRAWERS (drawers.js). Pete, 2026-10-10: "I want it to look very similar to
   CCleaner, but with two drawers." The same rows, re-homed: a slim top bar (the status row), a
   drawer on each side — every logo beside its words, a ☰ folds a drawer to its icons — and the
   page in its own rounded panel between them. Picked in Customize Design (prefs.layout); Layout 1
   is the strip above, untouched. The window never scrolls here: the frame is the viewport and
   the page scrolls inside its panel. Every measure is a token: --drawer-w, --rail-w, --topbar-h,
   in rem (13.75 / 3.5 / 3 — about 220 / 56 / 48 pixels at the default text size, CCleaner's own
   proportions), moved by Customize Design. No motion: a fold is instant.
   ========================================================================= */

:root[data-layout='drawers'],
:root[data-layout='drawers'] body { height: 100%; overflow: hidden; }
:root[data-layout='drawers'] #app { padding-top: 0; height: 100vh; height: 100dvh; display: flex; flex-direction: column; }
/* the strip has been taken apart; what is left of it takes no room */
:root[data-layout='drawers'] .strip--drawers { display: none; }

.frame2 {
  display: flex;
  align-items: stretch;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  gap: var(--pad);
  padding: var(--pad);
  background: var(--bg);
}

/* ---- a drawer: open at --drawer-w, folded to its icons at --rail-w ---- */
/* (v16) each drawer as wide as the person dragged it (drawers.js sets --dw on the drawer itself; none = --drawer-w,
   the token Customize Design moves) — never more than --drawer-max of the window, so a window made narrower takes a
   kept width down with it, and gives it back when it grows */
.drawer { --dw: var(--drawer-w); }
.drawer {
  flex: 0 0 min(var(--dw), var(--drawer-max));
  width: min(var(--dw), var(--drawer-max));
  min-width: 0;
  container: drawer / inline-size;   /* (v16) what is in it can ask how wide it is — the top line below */
  display: flex;
  flex-direction: column;
  gap: var(--pad);
  padding: var(--pad);
  background: var(--panel);
  border: var(--border);
  overflow-x: hidden;
}
.drawer[data-state='rail'] { flex-basis: var(--rail-w); width: var(--rail-w); }
.drawer__top { display: flex; align-items: center; flex: 0 0 auto; }
/* (v20) THE TOP LINE STAYS PUT (Pete, 2026-10-14: "when scrolling through the hamburgers the top line should always stay
   fixed"): the ☰ and what is beside it — the Vantage lockup on the left, the theme on the right — stick to the top of
   the drawer while the rest scrolls under them, exactly where they are at rest, on their
   own ground — reaching over the drawer's padding with a band of the panel's colour (a spread shadow: the line's own
   box is not changed by a hair, so nothing on it moves), so nothing that scrolls shows above or beside it. A list
   opened under it (Vantage's, the themes) scrolls in its own box rather than pinning the whole drawer. */
.drawer > .drawer__top { position: sticky; top: 0; z-index: 6; background: var(--panel); box-shadow: 0 0 0 var(--pad) var(--panel); }   /* (top 0: the browser measures a sticky line from inside the drawer's padding, so 0 IS where it lies at rest) */
.drawer[data-state='rail'] > .drawer__top { box-shadow: 0 0 0 calc(var(--pad) / 2) var(--panel); }
.drawer__top .doorway__list, .drawer__top .theme__list { max-height: 60vh; overflow-y: auto; }
.drawer--left .drawer__top { justify-content: flex-start; }
.drawer--right .drawer__top { justify-content: flex-end; }
.drawer[data-state='rail'] .drawer__top { justify-content: center; }
/* (v16) THE VANTAGE LOGO TO THE RIGHT OF THE ☰ (Pete, 2026-10-13): the left drawer's top line is the ☰, then the
   lockup with the build beside it — the header's size, as tall as the ☰, so the line is no taller than it was. The
   doorway itself takes no box here: its lockup is the line's second item and its list, opened, the line's own next
   line at the drawer's whole width (an expansion in place, as ever). Where the drawer is dragged narrow the word
   gives way and the V and the build stay. */
.drawer--left .drawer__top { flex-wrap: wrap; align-items: stretch; gap: calc(var(--pad) / 2); }
.drawer__top > .doorway { display: contents; }
.drawer--left .drawer__top .doorway--big .doorway__logo-box { flex: 1 1 0; width: auto; min-width: 0; align-self: stretch; display: flex; align-items: center; justify-content: flex-start; gap: calc(var(--pad) / 2); padding: 0 calc(var(--pad) / 2); overflow: hidden; }
/* the lockup's size follows the drawer's width: the header's size at most, and as large as fits beside the ☰ and the
   build (about 6.3 of its sizes wide, and 5.4rem taken by the ☰, the gaps and the build) — never squeezed out of shape
   (more particular than .drawer .lockup, below) */
.drawer--left .drawer__top .lockup { --lk: clamp(0.75rem, calc((100cqi - 5.4rem) / 6.6), min(calc(var(--topbar-h) * 0.42), var(--t-label))); flex: 0 0 auto; }
.drawer__build { flex: 0 0 auto; font-size: var(--t-small); color: var(--text2); white-space: nowrap; }
.drawer__top .doorway__list { order: 2; }
@container drawer (max-width: 11.5rem) { .drawer__top .lockup__word { display: none; } .drawer__top .lockup { gap: 0; } }
/* folded to the rail, the line stands up: the ☰, the V, the build */
.drawer[data-state='rail'] .drawer__top { flex-direction: column; align-items: center; }
.drawer--left[data-state='rail'] .drawer__top .doorway--big .doorway__logo-box { flex: 0 0 auto; width: 100%; flex-direction: column; justify-content: center; gap: calc(var(--pad) / 4); padding: calc(var(--pad) / 2) 0; }
/* (v17) THE THEME DROPDOWN, LEFT OF THE RIGHT ☰ (Pete, 2026-10-14): the right drawer's top line is the face and the ☰;
   the list, opened, is the line's own next line at the drawer's whole width — an expansion in place, as the left
   drawer's Vantage list is. The face's words wrap before they clip; the swatch is the design's own colour. */
.drawer--right .drawer__top { flex-wrap: wrap; align-items: stretch; gap: calc(var(--pad) / 2); }
.drawer__top > .theme { display: contents; }
.theme__face { flex: 1 1 0; width: auto; min-width: 0; display: flex; align-items: center; justify-content: flex-start; gap: calc(var(--pad) / 2); padding: calc(var(--pad) / 2); text-align: left; }
.theme__words { flex: 1 1 0; min-width: 0; white-space: nowrap; overflow: hidden; }   /* one line: the mode's words go where they do not fit whole (theme.js) */
.theme__name, .theme__mode { display: inline-block; white-space: nowrap; }
.theme__mode[hidden] { display: none; }
.theme__caret { flex: 0 0 auto; }
.theme__swatch { flex: 0 0 auto; width: 1.15em; height: 1.15em; border-radius: 0.3em; border: var(--border); background: var(--theme-band, none) center bottom / 100% 35% no-repeat, var(--theme-face, var(--card)); }
.theme__list { order: 2; flex: 1 1 100%; width: 100%; display: flex; flex-direction: column; gap: var(--pad); }
.theme__list[hidden] { display: none; }
.theme__group { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); }
.theme__head { text-transform: capitalize; }
.theme__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); gap: calc(var(--pad) / 2); }
.theme__entry { font: inherit; font-size: var(--t-label); line-height: var(--lh); min-width: 0; cursor: pointer; text-align: center; overflow-wrap: anywhere;
  color: var(--theme-ink, var(--text)); border: var(--border);
  background: var(--theme-band, none) center bottom / 100% 0.45em no-repeat, var(--theme-face, var(--card));
  padding: calc(var(--pad) / 2) calc(var(--pad) / 2) calc(var(--pad) / 2 + 0.45em); }
.theme__entry:hover { filter: brightness(1.08); }
.theme__entry.is-selected { outline: var(--selected-border); outline-offset: 0.12rem; }   /* (the same face picked or not: nothing beside it moves) */
/* folded to the rail: the swatch alone, under the ☰ */
.drawer[data-state='rail'] .theme__words, .drawer[data-state='rail'] .theme__caret, .drawer[data-state='rail'] .theme__list { display: none; }
.drawer[data-state='rail'] .theme__face { flex: 0 0 auto; width: 100%; justify-content: center; order: 1; }
.drawer__burger, .drawer__opener { width: auto; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; padding: calc(var(--pad) / 2); }
.drawer__burger > svg, .drawer__opener > svg { width: var(--t-card); height: var(--t-card); display: block; }
/* the groups keep their row tints and their rows' button hues ([data-row=…] above) */
.drawer__group { display: flex; flex-direction: column; gap: var(--pad); width: 100%; flex: 0 0 auto; padding: calc(var(--pad) / 2); }
.drawer__entry:empty { display: none; }

/* a doorway in a drawer: the logo beside its words, the list an EXPANSION under them — in place, never floating */
.drawer .doorway { flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: flex-start; gap: var(--pad); width: 100%; flex: 0 0 auto; }
.drawer .doorway__logo-box { width: auto; flex: 0 0 auto; }
.drawer .doorway__face { flex: 1 1 0; width: auto; min-width: 0; text-align: left; white-space: normal; overflow: visible; text-overflow: clip; }   /* the words beside the logo; two lines before they clip */
.drawer .doorway__list { position: static; flex: 1 1 100%; width: 100%; margin-top: 0; max-height: none; overflow: visible; }
/* the person: their mark and name take the line, the short face (Sign in / My Account) keeps its width */
.drawer [data-doorway='user'] .doorway__logo-box { flex: 1 1 0; min-width: 0; justify-content: flex-start; }
.drawer [data-doorway='user'] .doorway__face { flex: 0 0 auto; white-space: nowrap; }
.drawer .user-id { min-width: 0; }
/* Vantage at the top: the lockup is the whole line, and a click on it is the expansion (Pete, 2026-10-10) */
.drawer .doorway--big .doorway__logo-box { flex: 1 1 100%; width: 100%; align-self: auto; justify-content: flex-start; }
.drawer .lockup { --lk: var(--t-card); }
/* logos at icon size, beside their words — scaled so the LETTERS of each come out about equal */
.drawer .doorway__logo { height: var(--t-card); }
.drawer .doorway__logo--egan { height: calc(var(--t-card) * 1.45); }
.drawer .doorway__logo--solway { height: calc(var(--t-card) * 1.6); }
.drawer .doorway__logo--ottertail { height: calc(var(--t-card) * 1.35); }
.drawer .user-mark { height: calc(var(--t-card) * 1.3); width: calc(var(--t-card) * 1.3); }

/* the tools and the view row: a column of icon-beside-label rows; a pair's two choices expand under it */
.drawer .dropdown { flex-direction: column; align-items: stretch; gap: var(--pad); }
.drawer .dropdown__group { flex-direction: column; }
.drawer .dropdown__wide { justify-content: flex-start; width: 100%; min-width: 0; font-size: var(--t-label); white-space: normal; text-align: left; }   /* icon beside its words; the words wrap before they clip */
.drawer .dropdown__wide > span { min-width: 0; }
.drawer .dropdown__list { position: static; width: 100%; min-width: 0; margin-top: 0; max-height: none; }

/* the entry page's header, in the left drawer (task.js): one thing per line */
.drawer .entry__filters { position: static; top: auto; }
.drawer .entry__title { flex-direction: column; align-items: flex-start; }
/* (v52, v53) the four views: two lines of two — Racking · Wiring, Remediation · Housekeeping */
.drawer .entry__views { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.drawer .entry__views > .btn { width: 100%; min-width: 0; }
.drawer .entry__views > .btn { padding-inline: calc(var(--pad) / 4); hyphens: manual; overflow-wrap: normal; word-break: normal; }   /* (v53: two lines of two) */
.drawer .crewgrid { grid-template-columns: 1fr; }
.drawer .entry__field { flex: 1 1 100%; }
.drawer .entry__bar { flex-direction: column; align-items: stretch; }

/* folded to the rail: the icons stay, the words go; the view row and the entry header wait for the unfold */
.drawer[data-state='rail'] .doorway__face,
.drawer[data-state='rail'] .doorway__list,
.drawer[data-state='rail'] .user-id__name,
.drawer[data-state='rail'] .lockup__word,
.drawer[data-state='rail'] .drawer__filters,
.drawer[data-state='rail'] .drawer__entry,
.drawer[data-state='rail'] .dropdown__wide > span,
.drawer[data-state='rail'] .dropdown__face,
.drawer[data-state='rail'] .dropdown__group > .dropdown__list,
.drawer[data-state='rail'] .back > span,
.drawer[data-state='rail'] .rowsctl,
.drawer[data-state='rail'] .banner__view,
.drawer[data-state='rail'] .drawer__dialogue,
.drawer[data-state='rail'] .drawer__status { display: none; }
.drawer[data-state='rail'] .drawer__nav > .back { justify-content: center; padding: calc(var(--pad) / 2); }
.drawer[data-state='rail'] { padding: calc(var(--pad) / 2); }
.drawer[data-state='rail'] .drawer__group { padding: calc(var(--pad) / 4); align-items: center; }
.drawer[data-state='rail'] .doorway { justify-content: center; }
.drawer[data-state='rail'] .doorway__logo-box { width: 100%; justify-content: center; }
.drawer[data-state='rail'] .doorway--big .doorway__logo-box { justify-content: center; padding: calc(var(--pad) / 2); }
.drawer[data-state='rail'] .doorway__logo { height: auto; width: 100%; max-height: calc(var(--t-card) * 1.6); object-fit: contain; }
.drawer[data-state='rail'] .lockup { gap: 0; }
.drawer[data-state='rail'] .dropdown__wide { justify-content: center; padding: calc(var(--pad) / 2); }
.drawer[data-state='rail'] .dropdown__wide > svg { margin: 0; }

/* ---- Back, the Rows control and Admin/Worker: a group under the logos in the left drawer (Pete, 2026-10-10) ---- */
.drawer__nav > .btn, .drawer__nav > .back { width: 100%; font-size: var(--t-label); justify-content: flex-start; }
.drawer .rowsctl { position: static; flex-direction: column; width: 100%; gap: calc(var(--pad) / 2); }
.drawer .rowsctl__face { width: 100%; justify-content: space-between; }
/* the five expand IN PLACE under the face — an expansion, never a floating list */
.drawer .rowsctl__list { position: static; display: flex; flex-direction: column; gap: calc(var(--pad) / 2); width: 100%; padding: calc(var(--pad) / 2) 0 0; }
.drawer .rowsctl__list > .btn { width: 100%; justify-content: flex-start; }

/* ---- the dialogue box in the RIGHT drawer (Pete, 2026-10-10: "dialogue box is in the right panel"), under the
   person and the customer, one column. (v29 — Pete, 2026-10-16: "for the dialog box I want to move the input box on top
   and have the response box on the bottom and I want it to automatically expand down until it reaches the status
   lights") THE INPUT ON TOP, THE RESPONSE UNDER IT, DOWN TO THE LIGHTS: the input keeps its height (the lines as built,
   or as last dragged); the response takes every bit of the drawer left between the input and the lights at its foot,
   whatever the window's height, and what is said scrolls inside it — newest first, next to the input — so nothing said
   moves the lights. Its words never size it (size containment): a long session is not a taller box. Where the drawer
   is too short for both at their as-built height, the response keeps that height and the drawer scrolls, as before.
   The grip has nothing to set here and is not there. ---- */
.drawer .dialogue { grid-template-columns: minmax(0, 1fr); grid-template-areas: 'entry' 'say'; grid-template-rows: auto 1fr; width: 100%; flex: 1 1 0; }
.drawer .dialogue__say { height: auto; min-height: var(--dialogue-say-height); contain: size; }
.drawer .dialogue__grip { display: none; }
/* (v64) ONE POLYGON (Pete, 2026-10-21: "combine the input box and the readout box in the same polygon but make the input box
   a slightly more white or clear color than the readout box"): the box itself is the shape — the response's fill, its own
   border and corners, nothing around it — the input its top part, a little whiter (--dialogue-input-fill), the response
   under it, one line between them. No Inbox · Text Crew strip here (dialogue.js standing(false), drawers.js v14). */
.drawer .dialogue { gap: 0; padding: 0; background: var(--dialogue-fill); color: var(--dialogue-ink); }
.drawer .dialogue__entry { gap: 0; }
/* (the box's own corners carried into its two parts — never overflow: hidden, which would let the drawer squeeze the box) */
.drawer .dialogue__input { background: var(--dialogue-input-fill); border: 0; border-bottom: var(--border); border-radius: 0; border-top-left-radius: inherit; border-top-right-radius: inherit; }
.drawer .dialogue__entry { border-top-left-radius: inherit; border-top-right-radius: inherit; }
.drawer .dialogue__say { background: transparent; border-radius: 0; border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; }
/* the readouts — phase · mode · data — at the drawer's foot, small */
.drawer__status { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: calc(var(--pad) / 2); margin-top: auto; font-size: var(--t-small); color: var(--text2); }
.drawer__status .status__item { margin-left: 0; }
/* EVERY LIGHT, LISTED DOWN (Pete, 2026-10-11: "all of the LED lights in the right hamburger with a description of what
   the LED is for to the right"): the light, its name, what it watches — and, when it is not green, why. A tap opens
   the Health Check. The header carries ONE light for all of them. */
.leds { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); width: 100%; cursor: pointer; }
.led { display: flex; align-items: flex-start; gap: calc(var(--pad) / 2); min-width: 0; }
.led > .dot { flex: 0 0 auto; margin: 0.28em 0 0; }
.led__text { flex: 1 1 auto; min-width: 0; color: var(--text2); overflow-wrap: anywhere; }
.led__text b { color: var(--text); font-weight: 700; }
.led__why { display: block; color: var(--text); }
.led__why[hidden] { display: none; }

/* ---- the main column: THE HEADER, then the page in its own panel — the map or the PDF, nothing else ---- */
.main { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: var(--pad); }
/* the header holds three things (Pete, 2026-10-10): the mark and the build, the Map | PDF switch, the lights — (v16)
   and the job site's name; on a wide screen the mark and the build are beside the left drawer's ☰ instead */
.header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--pad);
  height: var(--topbar-h);
  min-height: var(--topbar-h);
  padding: 0 var(--pad);
  background: var(--panel);
  border: var(--border);
  white-space: nowrap;
  overflow: hidden;
}
.header .btn { padding-top: calc(var(--pad) / 2); padding-bottom: calc(var(--pad) / 2); }
/* (v37) the job site's doorway and the tools on a wide screen (drawers.js v9 placeTop) */
.header { container: hdr / inline-size; }
.frame2:not([data-phone='true']) .header { overflow: visible; position: relative; z-index: 6; }
.frame2:not([data-phone='true']) .header__site { display: none; }   /* (its doorway stands there instead) */
.header[data-door='jobsite'] .header__site { display: none; }   /* (v42) at every width, the phone's too */
.frame2[data-phone='true'] .header .doorway__face { display: none; }   /* (v42) on a phone the job site is its logo alone — a tap on it opens its list */
.frame2[data-phone='true'] .header .doorway { margin-right: calc(var(--pad) / 2); }
.header .doorway[hidden] { display: none; }   /* (v42) a phone too narrow for the logo: left out, never squeezed (drawers.js v10) */
.header [data-row] { background: none; }
.header .doorway { flex: 0 0 auto; align-self: stretch; flex-direction: row; align-items: center; justify-content: flex-start; gap: calc(var(--pad) / 2); }   /* (as tall as the header: its list drops from the header's foot) */
.header .doorway__logo-box { width: auto; }
.header .doorway__logo { height: calc(var(--topbar-h) * 0.6); }
.header .doorway__face { flex: 0 0 auto; width: auto; font-size: var(--t-label); font-weight: 700; padding-left: calc(var(--pad) / 2); padding-right: calc(var(--pad) / 2); }
.header .doorway__list { min-width: 16rem; white-space: normal; max-height: calc(100dvh - var(--topbar-h) - var(--pad) * 3); }   /* (v70) every entry seen at once where the screen has room — 14 lines cut the last one off */
.header__tools { display: flex; flex: 0 0 auto; min-width: 0; align-self: stretch; align-items: stretch; }
.header__tools:empty { display: none; }
.header .dropdown { flex: 0 0 auto; flex-direction: row; align-items: stretch; gap: calc(var(--pad) / 2); }
.header .dropdown__group { flex: 0 0 auto; align-items: center; }   /* (as tall as the header, the button in its middle: a list drops from the header's foot) */
.header .dropdown > .dropdown__wide { align-self: center; }
.header .dropdown__wide { flex: 0 0 auto; width: auto; font-size: var(--t-small); padding-left: calc(var(--pad) / 2); padding-right: calc(var(--pad) / 2); }
.header .dropdown__lead { display: none; }
.header .dropdown__group > .dropdown__list { min-width: 12rem; }
@container hdr (max-width: 62rem) { .header .dropdown__wide > span { display: none; } }   /* the tools' words go first … */
@container hdr (max-width: 44rem) { .header .doorway__face { display: none; } }          /* … then the job site's */
.drawer__tools:empty, .drawer__logos:empty { display: none; }
/* the mark and the build: SMALL — sized into the header, never the header grown to fit it (Pete, 2026-10-10) */
.header__mark { display: inline-flex; align-items: center; gap: calc(var(--pad) / 2); flex: 0 0 auto; background: none; border: 0; padding: 0; color: var(--text); font: inherit; cursor: pointer; }
.header .lockup { --lk: min(calc(var(--topbar-h) * 0.42), var(--t-label)); }
.header__build { font-size: var(--t-small); color: var(--text2); }
.header .switch { flex: 0 0 auto; font-size: var(--t-small); }
.header__space { flex: 1 1 auto; min-width: 0; }
/* the lights: the data light and the four Health Check lights, no words beside them while all are green; one amber
   or red → the faults and why, to their right (the full list on hover; a tap opens the Health Check) */
/* (v75) Pete's own: Sync then Refresh, one group a hair apart, before the light */
.header__owngroup { flex: 0 0 auto; display: inline-flex; align-self: stretch; align-items: stretch; column-gap: calc(var(--pad) / 4); }
.header__owngroup[hidden], .header__owngroup[data-empty] { display: none; }
.header__own { width: auto; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; padding: 0 calc(var(--pad) / 2); align-self: stretch; margin-block: calc(var(--pad) / 4); font-size: var(--t-card); line-height: 1; }   /* (v72) Pete's Refresh — (v75) and Sync */
.header__own[hidden], .header__own[data-noroom] { display: none; }   /* (v72) a phone's sliver with no room for it after the job site's logo */
.frame2[data-phone='true'] .header__own { padding: 0; min-width: 1em; font-size: var(--t-label); }   /* (v72) compact on a phone's sliver: the glyph's own width — (v75) the label's size, so both stand beside the logo on a 412 */
.header__sync[data-running] { background: var(--light-amber); color: var(--dialogue-ink); }   /* (v75) a sync running: the amber of a light still working, its glyph dark on it */
.header__leds { display: inline-flex; align-items: center; gap: calc(var(--pad) / 2); flex: 0 0 auto; background: none; border: 0; padding: 0 calc(var(--pad) / 2); cursor: pointer; }
.header__leds .dot { margin-right: 0; }
.header__why { flex: 0 1 auto; min-width: 0; max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--t-small); color: var(--text); }
.header__why[hidden] { display: none; }
.main__page {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--pad);
  background: var(--panel);
  border: var(--border);
}
.main__page > .frame, .main__page > .home > .frame { padding: 0; }   /* the home page's frame sits one level in — the panel's own padding is the only one */
/* THE PANEL IS THE CARD (Pete, 2026-10-11: "when viewing the PDF, we don't need a card within a card, just the one —
   the centre main window is now the viewport; whatever the user is working on should be in that main viewport").
   The view's own boxes — the viewer's box, a block's panel, a section's card, the map's frame — draw no surface, no
   border and no padding of their own in this layout: what is being worked on sits directly in the panel. The block's
   header still sticks to the top of the panel as the pages scroll under it. */
:root[data-layout='drawers'] .main__page .entry__view .viewer__box,
:root[data-layout='drawers'] .main__page .entry__view .viewer__box > .panel,
:root[data-layout='drawers'] .main__page .entry__view .viewer__box .card.section,
:root[data-layout='drawers'] .main__page .entry__view .atlas .map { background: transparent; border: 0; border-radius: 0; padding: 0; box-shadow: none; }
:root[data-layout='drawers'] .main__page .entry__view .viewer__box .block__head { padding-bottom: calc(var(--pad) / 2); }
/* the sticky furniture inside a page sticks to the panel it scrolls in, not the window */
:root[data-layout='drawers'] .entry__filters,
:root[data-layout='drawers'] .side__main,
:root[data-layout='drawers'] .side__aside { top: 0; }
/* the openers are for the phone; on a wide screen each drawer carries its own ☰ */
.frame2[data-phone='false'] .drawer__opener { display: none; }
/* (v16) on a wide screen the mark and the build are beside the left drawer's ☰ — not again on the header */
.frame2[data-phone='false'] .header__mark { display: none; }
/* (v16) THE JOB SITE'S NAME ON THE HEADER (Pete, 2026-10-13: "solway solar should be on the thin header above the
   viewport"): its first word on a wide screen, beside the mark on a phone. A click is home. Never cut short — where
   there is no room for all of it, drawers.js leaves it out; the faults beside the light give way before it does. */
.header__site { flex: 0 1 auto; min-width: 0; overflow: hidden; display: flex; background: none; border: 0; padding: 0; color: var(--text); font: inherit; font-size: var(--t-label); font-weight: 700; cursor: pointer; }
.header__sitename { flex: 0 0 auto; white-space: nowrap; }   /* (never shrinks: its width is the name's whole width — drawers.js reads it to know whether it fits) */
.header__site[hidden] { display: none; }
.frame2[data-phone='true'] .header__site { font-size: var(--t-small); margin-right: calc(var(--pad) / 2); }   /* (a phone's gaps are half: the name stands a little apart from the switch's Map) */
.header__why { flex-shrink: 50; }

/* ---- (v16) THE DRAWERS ARE AS WIDE AS THEY ARE DRAGGED (Pete, 2026-10-13: "the side drawers need to be able to be
   adjustable width"). A grip lies in the gap on each drawer's inner edge: no width of its own in the row (it stands
   back a gap, so the gaps are as they were), the gap itself — a hair more each side — is what takes the pointer. A
   line shows in the gap under the pointer, with the focus and while dragging. Not there for a rail, nor on a phone. */
.drawer__grip { flex: 0 0 0; width: 0; align-self: stretch; margin-left: calc(-1 * var(--pad)); position: relative; z-index: 5; touch-action: none; outline: none; cursor: col-resize; }
.drawer__grip[hidden] { display: none; }
.drawer__grip::before { content: ''; position: absolute; top: 0; bottom: 0; left: -0.125rem; width: calc(var(--pad) + 0.25rem); cursor: col-resize; }
.drawer__grip::after { content: ''; position: absolute; top: 0; bottom: 0; left: calc(var(--pad) / 2 - 0.0625rem); width: 0.125rem; border-radius: 0.0625rem; background: var(--text2); opacity: 0; pointer-events: none; }
.drawer__grip:hover::after, .drawer__grip:focus-visible::after, .frame2[data-sizing='left'] > .drawer__grip--left::after, .frame2[data-sizing='right'] > .drawer__grip--right::after { opacity: 1; }
/* while an edge is dragged nothing is selected and the pointer says what it is doing wherever it is */
.frame2[data-sizing] { user-select: none; -webkit-user-select: none; }
.frame2[data-sizing] * { cursor: col-resize; }

/* ---- full screen: both drawers away; the header stays and shows its two ☰, which bring them back (drawers.js) ---- */
:root[data-hide-banner='true'][data-hide-tools='true'][data-hide-filters='true'][data-hide-dialogue='true'] .frame2 > .drawer,
:root[data-hide-banner='true'][data-hide-tools='true'][data-hide-filters='true'][data-hide-dialogue='true'] .frame2 > .drawer__grip { display: none; }
:root[data-hide-banner='true'][data-hide-tools='true'][data-hide-filters='true'][data-hide-dialogue='true'] .frame2 .drawer__opener { display: inline-flex; }
:root[data-hide-banner='true'][data-hide-tools='true'][data-hide-filters='true'][data-hide-dialogue='true'] .frame2 .header__mark { display: inline-flex; }   /* (v16) and the mark, with the drawers away

/* ---- (v67) THE SIGN-IN PAGE: no drawers (Pete, 2026-10-22: "the drawers should not be open at the login screen") — nothing
   in them works for nobody, so nothing of them is drawn; the header keeps the mark alone ---- */
.frame2[data-signedout] > .drawer,
.frame2[data-signedout] > .drawer__grip,
.frame2[data-signedout] .drawer__opener,
.frame2[data-signedout] .header > :not(.header__mark):not(.header__space) { display: none; }
.frame2[data-signedout] .header__mark { display: inline-flex; }

/* ---- a phone: the drawers lie OVER the page (Pete, 2026-10-03), shut until the top bar opens one ---- */
.frame2[data-phone='true'] > .drawer {
  position: fixed;
  top: 0;
  bottom: 0;
  z-index: 6;
  width: var(--drawer-phone-w);   /* two thirds of the screen (Pete, 2026-10-11) — it was the desktop's width, about half */
  flex-basis: auto;
  margin: 0;
}
.frame2[data-phone='true'] > .drawer--left { left: 0; }
.frame2[data-phone='true'] > .drawer--right { right: 0; }
.frame2[data-phone='true'] > .drawer[data-state='shut'] { display: none; }
/* one sliver of a header on a phone (Pete, 2026-10-10): the ☰ at each end, the mark, the switch, the lights */
.frame2[data-phone='true'] .header { height: var(--topbar-phone-h); min-height: var(--topbar-phone-h); gap: calc(var(--pad) / 2); padding: 0 calc(var(--pad) / 2); }
.frame2[data-phone='true'] .header .lockup { --lk: min(calc(var(--topbar-phone-h) * 0.42), var(--t-label)); }
.frame2[data-phone='true'] .header__why { display: none; }
/* the sliver has room for the mark's V and the build, not the wordmark */
.frame2[data-phone='true'] .header .lockup__word { display: none; }
.frame2[data-phone='true'] .header .lockup { gap: 0; }

/* ---- (v34) HAND & SCAN — the PDF's own bar, and the crews' scanned sheets in each section's place (task.js v45, scans.js) ---- */
.viewer__face { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); flex: 0 0 auto; min-width: 0; }
/* (v48) THE PDF VIEW'S LINES: each one line that slides sideways (chiprow.js), its parts whole */
.viewer__row { flex: 0 0 auto; flex-wrap: nowrap; gap: calc(var(--pad) / 2) var(--pad); min-width: 0; }
.viewer__row > *, .viewer__row .viewer__controls > * { flex: 0 0 auto; }
.viewer__row .viewer__controls { flex-wrap: nowrap; }
.viewer__row .block__pick { max-width: none; }
.viewer__tasks { gap: calc(var(--pad) / 2) calc(var(--pad) * 1.5); }
.viewer__tasks > .switch-row { display: inline-flex; align-items: center; gap: calc(var(--pad) / 2); width: auto; flex: 0 0 auto; min-width: max-content; }
.viewer__tasks > .switch-row > * { flex: 0 0 auto; }
.viewer__tasks .t-label, .viewer__tasks .btn { white-space: nowrap; }
.viewer__row .viewer__faceline { flex: 0 0 auto; height: auto; display: block; white-space: nowrap; overflow: visible; -webkit-line-clamp: none; }
.entry__tasks { flex: 0 0 auto; min-width: 0; display: flex; flex-direction: column; gap: calc(var(--pad) / 2); }
/* (v51) the tasks under the PDF: a list, top to bottom — in columns where the view is wide, scrolling up and down in its own box where it is long */
.viewer__taskhead { display: flex; align-items: center; gap: var(--pad); flex: 0 0 auto; min-width: 0; }
.viewer__taskhead .t-label { white-space: nowrap; }
.viewer__tasklist { flex: 0 0 auto; min-width: 0; max-height: min(30vh, 24rem); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
.viewer__taskcols { columns: 17rem; column-gap: calc(var(--pad) * 3); }
.viewer__taskcols > * { break-inside: avoid; margin-bottom: calc(var(--pad) / 2); }
.viewer__taskcols > .switch-row { display: flex; align-items: center; gap: var(--pad); width: 100%; min-width: 0; }
.viewer__taskcols > .switch-row > .switch { flex: 1 1 auto; min-width: 0; }
.viewer__taskcols > .switch-row > .btn { flex: 0 0 auto; width: auto; }
/* (v84) ↑ ↓ before each task's switch: the same square at every line, a gap of its size where one end has nowhere to go */
.switch-row__mvs { display: inline-flex; gap: calc(var(--pad) / 3); flex: 0 0 auto; }
.switch-row__mvs > .switch-row__mv { width: auto; min-width: 2.25rem; padding-inline: 0; justify-content: center; }
.switch-row__mvgap { display: inline-block; width: 2.25rem; flex: 0 0 auto; }
.viewer__taskcols .switch__name { white-space: normal; overflow-wrap: anywhere; text-align: left; }
.viewer__taskcols > a.btn { display: inline-flex; width: auto; }
.viewer__box { touch-action: pan-x pan-y; }
/* what the face shows: two lines' room always, so a longer sentence never moves the box under it */
.viewer__faceline { flex: 1 1 14rem; min-width: 0; height: calc(var(--lh) * 2em); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.scanset { gap: var(--gap); }
.scan { margin: 0; display: flex; flex-direction: column; gap: calc(var(--pad) / 2); min-width: 0; }
.scan__fit { width: 100%; max-width: none; background: var(--sheet-paper, var(--card)); border: var(--border); overflow: hidden; flex: 0 0 auto; }
.scan__fit[data-failed='true'] { background: var(--raised); }
.scan__img { display: block; width: 100%; height: 100%; object-fit: contain; cursor: zoom-in; }
.scan__img:not([src]) { visibility: hidden; }
.scan__fit { position: relative; }
.scan__marks { position: absolute; inset: 0; pointer-events: none; transform-origin: 50% 50%; }
.scan__img:not([src]) + .scan__marks, :root[data-scan-marks-off] .scan__marks { display: none; }
.scan__mark { position: absolute; box-sizing: border-box; border: 0.12rem solid var(--light-red); background: color-mix(in oklch, var(--light-red) 22%, transparent); }
.scan__cap > .scan__blank.t-small { flex: 1 1 100%; display: block; min-width: 0; }   /* (its own line under the name and the buttons) */
.scan__blank > .dot { display: inline-block; vertical-align: middle; margin-right: 0.4em; }
.scan__blanklist { display: block; }
.scan__cap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: calc(var(--pad) / 2) var(--pad); min-width: 0; }
.scan__cap > .t-small { flex: 1 1 14rem; min-width: 0; }
.scan__acts { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); }
.scan__none { display: flex; align-items: center; gap: calc(var(--pad) / 2); padding: var(--pad); background: var(--raised); border: var(--border); }
.scan__part { margin: 0; color: var(--text); }

/* ---- (v34) CREW LEADER TASK SHEETS (#tasksheets — scans.js page) ---- */
.tasksheets__sum { margin: 0; }
.tasksheets__grid { overflow: auto; max-height: 70vh; border: var(--border); border-radius: var(--radius-cap); background: var(--panel); }
.tasksheets__row { display: grid; grid-template-columns: minmax(11rem, 1.2fr) repeat(8, minmax(7.5rem, 1fr)); min-width: 74rem; border-bottom: var(--border); }
.tasksheets__row > * { padding: calc(var(--pad) / 2); min-width: 0; display: flex; align-items: center; gap: 0.25em; }
.tasksheets__row--head { position: sticky; top: 0; z-index: 2; background: var(--panel); }
.tasksheets__where { position: sticky; left: 0; z-index: 1; background: var(--panel); white-space: nowrap; }
.tasksheets__cell.is-open { cursor: pointer; }
.tasksheets__cell.is-open:hover { background: var(--card-hover); }
.tasksheets__missing h3 { margin: 0; }
.tasksheets__faces a[aria-current='page'] { outline: var(--selected-border); outline-offset: 0; }
.blankcells__kind[aria-pressed='true'] { border: var(--border); outline: var(--selected-border); outline-offset: 0; }   /* (a ring, never a heavier border — the chips beside it stay put) */
.blankcells__block { width: auto; font: inherit; font-size: var(--t-body); }
.blankcells__head { position: sticky; top: 0; z-index: 2; margin: 0; padding: calc(var(--pad) / 2) 0; background: var(--bg); box-shadow: 0 calc(var(--pad) * -1) 0 0 var(--bg); }
.main__page .blankcells__head { background: var(--panel); box-shadow: 0 calc(var(--pad) * -1) 0 0 var(--panel); }   /* (the panel's own padding above it covered too: nothing that scrolls shows over a block's name) */
.blankcells__section h3 { margin: 0; }
.blankcells__sheet { padding: calc(var(--pad) / 2) 0; border-bottom: var(--border); }   /* (the panel is the card: a line between sheets, never a box) */
.blankcells__name { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: calc(var(--pad) / 2) var(--pad); min-width: 0; }
.blankcells__name > .t-small { flex: 1 1 14rem; min-width: 0; }
.blankcells__items { margin: 0; padding-left: 1.2em; display: flex; flex-direction: column; gap: 0.2em; }
.blankcells__tag { display: inline-block; padding: 0 0.4em; border: var(--border); border-radius: var(--radius-cap); font-weight: 500; }
.blankcells__tag.is-date { border-color: var(--light-red); }
.tasksheets__missing p { margin: 0; }
@media print {
  .tasksheets__grid { max-height: none; overflow: visible; }
  .tasksheets__bar { display: none; }
  .tasksheets__faces, .blankcells__kinds, .blankcells__name .scan__acts { display: none; }
  .blankcells__head { position: static; box-shadow: none; }
}


/* ---- (v39) TASKS FROM A SHEET'S COLUMNS (gsheet.js v2 — Make Tasks From Columns) and THEIR PDF, THE SHEET ITSELF (sheettasks.js) ---- */
.gsheet__makebtn[aria-pressed='true'] { outline: var(--selected-border); outline-offset: 0; }
.gsheet__make { padding: var(--pad); background: var(--card); border: var(--border); border-radius: var(--radius-cap); gap: calc(var(--pad) / 2); }
.gsheet__make p { margin: 0; }
.gsheet__roles, .gsheet__rows { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2) var(--pad); }
.gsheet__role[aria-pressed='true'] { border: var(--border); outline: var(--selected-border); outline-offset: 0; }   /* (a ring, never a heavier border) */
.gsheet__num-in { width: 5rem; }
.gsheet__crew-in { width: min(100%, 18rem); }
.gsheet__view-in { width: auto; }
.gsheet__box.is-picking .gsheet__letters > th[data-c] { cursor: pointer; }
.gsheet__box.is-picking .gsheet__letters > th[data-c]:hover { outline: var(--selected-border); outline-offset: -0.125rem; }
.sheetform { gap: var(--pad); min-width: 0; }
.sheetform__tab { gap: calc(var(--pad) / 2); min-width: 0; }
.sheetform__head { gap: var(--pad); flex-wrap: wrap; }
.sheetform__head > .btn { flex: 0 0 auto; }
.sheetform__box { height: auto; max-height: clamp(18rem, calc(100dvh - 16rem), 90rem); }
.sheetform__wait { width: 100%; height: 18rem; }
.sheetform__off { margin: 0; }
.sheetform__in { all: unset; box-sizing: border-box; display: block; width: 100%; min-height: 1.2em; font: inherit; color: inherit; text-align: inherit; cursor: text; }
.sheetform__in:focus { outline: 0.125rem solid var(--light-green); outline-offset: -0.125rem; background: color-mix(in oklch, var(--light-green) 14%, transparent); }
.gsheet__grid td.is-vantage { box-shadow: inset 0.25rem 0 0 var(--light-green); }   /* (entered in Vantage, standing over the sheet's own) */
.sheetform-print .sheetform__box { max-height: none; overflow: visible; border: 0; }
.sheetform-print .gsheet__grid th { display: none; }
@media print { .sheetform-print .gsheet__grid td, .sheetform-print .gsheet__grid { -webkit-print-color-adjust: exact; print-color-adjust: exact; } }


/* ---- (v56) THE LOGO IS THE DROPDOWN'S NAME (banner.js v12 — Pete, 2026-10-19): a rounded rectangle, the logo inside it and the
   arrow beside it, bigger than the words' arrow was; the whole rectangle is the button ---- */
:root { --door-caret: calc(var(--t-card) * 1.25); }   /* (a quarter past the card heading: clearly bigger than the label-sized arrow it replaces) */
.doorway--logo .doorway__logo-box { display: flex; flex-direction: row; align-items: center; justify-content: center; gap: calc(var(--pad) / 2); background: var(--card); border: var(--border); padding: calc(var(--pad) / 2) calc(var(--pad) * 0.75); cursor: pointer; color: var(--text); }
.doorway--logo .doorway__logo-box:hover { background: var(--card-hover); }
.doorway--logo .doorway__logo-box:focus-visible { outline: var(--selected-border); outline-offset: 0.12rem; }
.doorway--logo .doorway__logo-box[aria-expanded='true'] { outline: var(--selected-border); outline-offset: 0; }   /* (open: a ring, never a heavier border) */
.doorway__caret { flex: 0 0 auto; font-family: inherit; font-size: var(--door-caret); line-height: 1; font-weight: 700; color: var(--text); }
/* in a drawer: the rectangle hugs the logo and its arrow */
.drawer .doorway--logo:not(.doorway--big) .doorway__logo-box { flex: 0 0 auto; width: auto; justify-content: flex-start; }
/* Vantage on the left drawer's top line: ☰ · [the lockup, the build, the arrow] — the line no taller than the ☰; the lockup
   leaves room for the arrow too (it already did for the ☰, the gaps and the build) */
.drawer--left .drawer__top .doorway--big .doorway__logo-box { padding: 0 calc(var(--pad) / 2); }
.drawer--left .drawer__top .lockup { --lk: clamp(0.75rem, calc((100cqi - 5.4rem - var(--door-caret)) / 6.6), min(calc(var(--topbar-h) * 0.42), var(--t-label))); }
.drawer--left .drawer__top .doorway__caret { margin-left: auto; }
.drawer[data-state='rail'] .doorway__caret { display: none; }
.drawer[data-state='rail'] .doorway--logo .doorway__logo-box { padding: calc(var(--pad) / 4); justify-content: center; }
/* on the header: as tall as fits inside it, never the header grown */
.header .doorway--logo { align-self: stretch; }
.header .doorway--logo .doorway__logo-box { align-self: center; padding: calc(var(--pad) / 4) calc(var(--pad) / 2); max-height: calc(100% - var(--pad) / 2); }
.header .doorway--logo .doorway__logo { height: calc(var(--topbar-h) * 0.5); }
.frame2[data-phone='true'] .header .doorway--logo .doorway__logo { height: calc(var(--topbar-phone-h) * 0.5); }
.frame2[data-phone='true'] .header .doorway--logo .doorway__logo-box { gap: calc(var(--pad) / 4); padding: calc(var(--pad) / 4) calc(var(--pad) / 3); }
/* (v70) THE JOB SITE'S DROPDOWN IS NAMED — "Solway Solar - 366374" (Pete, 2026-10-22): in its rectangle on a wide header,
   else the first line of its list. The two are never both shown, and one of them always is. */
.doorway__name { display: none; flex: 0 1 auto; min-width: 0; font-size: var(--t-label); font-weight: 700; line-height: 1; white-space: nowrap; color: var(--text); }
.header .doorway__name { display: inline; }
.frame2[data-phone='true'] .header .doorway__name { display: none; }
.doorway__title { display: block; font-size: var(--t-small); font-weight: 700; padding: var(--pad); white-space: nowrap; color: var(--text); cursor: default; border-bottom: var(--border); margin-bottom: calc(var(--pad) / 4); }
.header .doorway__title { display: none; }
.frame2[data-phone='true'] .header .doorway__title { display: block; }
@container hdr (max-width: 44rem) { .header .doorway__name { display: none; } .header .doorway__title { display: block; } }
/* (v83) a page with no map or PDF: no switch on the header — and the job site's name in its rectangle, on a phone too, where
   it fits (the header's name steps aside first: data-noname) */
.header > .switch[hidden] { display: none; }
.header[data-noview]:not([data-noname]) .doorway__name { display: inline; }
.header[data-noview]:not([data-noname]) .doorway__title { display: none; }
.frame2[data-phone='true'] .header[data-noview] .doorway__name { font-size: var(--t-small); }   /* (on a phone's sliver: the small size, so it stands where the switch stood) */
.frame2[data-phone='true'] .header[data-noview]:not([data-noname]) .doorway--logo .doorway__logo-box { padding-inline: calc(var(--pad) / 3); column-gap: calc(var(--pad) / 8); }
/* (v70) on a phone the job site's list is SEEN: the sliver lets it out while it is open, and it is the sliver's width */
.frame2[data-phone='true'] .header { position: relative; }
.frame2[data-phone='true'] .header:has(> .doorway > .doorway__list:not([hidden])) { overflow: visible; z-index: 6; }
.frame2[data-phone='true'] .header > .doorway { position: static; }
.frame2[data-phone='true'] .header > .doorway > .doorway__list { left: 0; right: 0; width: auto; min-width: 0; max-height: calc(100dvh - var(--topbar-phone-h) - var(--pad) * 3); }   /* (every entry seen at once where the screen has room) */

/* ---- (v56) #onhold — what is off the menus for now, each still working ---- */
/* the panel is the card: a group is its heading and its buttons, never a box of its own inside it */
.onhold__group { background: transparent; border: none; box-shadow: none; padding-left: 0; padding-right: 0; }
.onhold__items { flex-wrap: wrap; }
.onhold__items > .btn { flex: 0 1 auto; width: auto; }

/* ---- (v61) #formtracker — the tracker's Form Tracker tab, as it is (formtracker.js) ---- */
/* the measures and colours are the tab's own, set on the page (--ft-*): sheet pixels as rem, points as the sheet viewer
   takes them, its fills and inks as OKLCH. The tab and the picked form are each a box of one height that scrolls. */
.ft { container: ft / inline-size; --ft-h: clamp(22rem, calc(100dvh - 11rem), 90rem); }
.ft { gap: calc(var(--pad) / 2); }   /* (v63) the top line close over the tab */
.ft__top { display: flex; flex-wrap: nowrap; align-items: center; gap: calc(var(--pad) / 2); overflow-x: auto; overflow-y: hidden; scrollbar-width: none; overscroll-behavior-x: contain; padding: 0.25rem; margin: -0.25rem; }   /* (the padding keeps the picked page's ring from being cut by the line's edge) */   /* (v63) ONE line: the title, Racking | Wiring, the two pickers */
.ft__top::-webkit-scrollbar { display: none; }
.ft__top > * { flex: 0 0 auto; }
.ft__title { margin: 0; font-size: var(--t-card); line-height: 1.1; white-space: nowrap; }
.ft__faces { flex-wrap: nowrap; gap: calc(var(--pad) / 2); }
.ft__faces > .btn, .ft__pick { font-size: var(--t-small); padding: calc(var(--pad) / 2) var(--pad); min-height: 0; line-height: 1.2; }
.ft__picks { flex-wrap: nowrap; }
@container ft (max-width: 40rem) { .ft__title { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } }   /* (v63) a phone: the ringed Racking | Wiring names the page */
.ft__faces a[aria-current='page'] { outline: var(--selected-border); outline-offset: 0; }
.ft__picks { display: flex; flex-wrap: wrap; gap: calc(var(--pad) / 2); }
.ft__pick { width: auto; max-width: 100%; field-sizing: content; font-weight: 700; }   /* (the tab's G1 and G2: bold) */
.ft__body { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--gap); align-items: start; min-width: 0; }
.ft__box { height: var(--ft-h); max-width: 100%; overflow: auto; overscroll-behavior: contain; background: var(--ft-paper); color: var(--ft-ink); border: var(--border); }
.ft__grid { border-collapse: separate; border-spacing: 0; table-layout: fixed; width: calc(var(--ft-sec) + var(--ft-ncols, 10) * var(--ft-cell)); font-family: Roboto, sans-serif; font-size: var(--ft-pt-cell); line-height: 1.2; color: var(--ft-ink); background: var(--ft-paper); }
.ft__grid th, .ft__grid td { border: 0; padding: 0; text-transform: none; }
.ft__colsec { width: var(--ft-sec); }
.ft__colcell { width: var(--ft-cell); }
.ft__headrow > th { position: sticky; top: 0; z-index: 2; height: auto; padding-block: 0.25rem; background: var(--ft-headfill); font-size: var(--ft-pt-head); font-weight: 700; text-align: center; vertical-align: middle; white-space: normal; overflow-wrap: break-word; padding-inline: 0.125rem; }   /* (v63) as tall as its names */
.ft__headrow > th.ft__corner { left: 0; z-index: 3; color: var(--ft-headink); text-align: left; padding-left: 0.1875rem; }
.ft__gaprow > td { height: 0.25rem; }   /* (v63) the tab's blank row under the header, a sliver */
.ft__row > * { height: var(--ft-row); }
.ft__sec, .ft__totalname { position: sticky; left: 0; z-index: 1; background: var(--ft-paper); text-align: left; vertical-align: middle; white-space: nowrap; padding-left: 0.1875rem; }
.ft__sec { font-weight: 400; }
.ft__pic { display: block; position: relative; width: var(--ft-cell); height: var(--ft-row); padding: 0.125rem; margin: 0; border: 0; border-radius: 0; background: transparent; color: var(--ft-ink); font: inherit; cursor: pointer; }
.ft__pic:hover, .ft__pic:focus-visible { box-shadow: inset 0 0 0 0.12rem var(--sheet-pick-colour); outline: none; }
.ft__pic[aria-pressed='true'] { box-shadow: inset 0 0 0 0.1875rem var(--sheet-pick-colour); }
.ft__img { display: block; width: 100%; height: 100%; object-fit: contain; }
.ft__img:not([src]) { visibility: hidden; }
/* a sheet in whose thumbnail is not made yet: a blank page, never an empty cell */
.ft__blankpage { display: block; width: 74%; height: 92%; margin: 4% auto 0; background: repeating-linear-gradient(to bottom, transparent 0 0.3rem, color-mix(in oklch, var(--ft-ink) 14%, transparent) 0.3rem 0.36rem), var(--ft-paper); border: 0.0625rem solid color-mix(in oklch, var(--ft-ink) 35%, transparent); }
.ft__n { position: absolute; right: 0.125rem; bottom: 0.125rem; min-width: 1.2em; padding: 0 0.2em; font-size: var(--ft-pt-cell); font-weight: 700; line-height: 1.3; text-align: center; color: var(--ft-headink); background: var(--ft-headfill); border-radius: 0.25rem; }
.ft__footgap > td { height: var(--ft-footgap); }
.ft__foot > * { height: var(--ft-foot); vertical-align: middle; }
.ft__totalname { font-weight: 700; }
.ft__total { text-align: center; white-space: nowrap; overflow: visible; }
.ft__also { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--pad) / 2); padding: var(--pad) 0.1875rem; width: calc(var(--ft-sec) + var(--ft-ncols, 10) * var(--ft-cell)); }
.ft__also:empty { display: none; }
.ft__alsoname { font-weight: 700; color: var(--ft-ink); }
.ft__alsopick[aria-pressed='true'] { outline: var(--selected-border); outline-offset: 0.15rem; }
.ft__view { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); height: var(--ft-h); min-width: 0; }
.ft__viewbar { display: flex; align-items: center; gap: calc(var(--pad) / 2); flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; flex: 0 0 auto; }
.ft__zoom { white-space: nowrap; }
.ft__up { display: none; }
.ft__said { margin: 0; flex: 0 0 auto; min-height: calc(var(--t-small) * var(--lh) * 3); }   /* (three lines' room: the pages under it never move as the pick changes) */
.ft__viewbox { flex: 1 1 0; min-height: 0; overflow: auto; overscroll-behavior: contain; touch-action: pan-x pan-y; display: flex; flex-direction: column; gap: var(--gap); }
.ft__viewbox > .scan { flex: 0 0 auto; }
/* a page under 70rem: the section column only as wide as its names, so the picked form keeps its room beside the tab */
@container ft (max-width: 70rem) {
  .ft__box { --ft-sec: 4.5rem; }
  .ft__totalname { white-space: normal; }
}
/* a narrow page: the tab, or the picked form in its place — Up to the Form Tracker brings the tab back as it was */
@container ft (max-width: 58rem) {
  .ft__body { grid-template-columns: minmax(0, 1fr); }
  .ft:not([data-open]) .ft__view { display: none; }
  .ft[data-open] .ft__box { display: none; }
  .ft__up { display: inline-flex; flex: 0 0 auto; }
}


/* ---- (v65) THE LEFT DRAWER, AS PETE LAID IT OUT (35.8, 2026-10-21) ---- */
/* Egan's rectangle: the drawer's whole width — its logo on the left, its arrow on the right */
.drawer--left .drawer__logos .doorway--logo .doorway__logo-box { flex: 1 1 100%; width: 100%; justify-content: space-between; }
.drawer--left[data-state='rail'] .drawer__logos .doorway--logo .doorway__logo-box { justify-content: center; }
/* the entry's two dropdowns — Print / Export, then View / Edit — no box of their own around them (the panel is the card) */
.drawer .entry__filters--drawer { background: transparent; border: none; box-shadow: none; padding: 0; gap: var(--pad); }
.entry__mapedit:empty { display: none; }
/* a drawer's dropdown (drawerdrop.js): the Egan rectangle's look, the drawer's width, its words left and its arrow right;
   what it holds IN PLACE under it */
.ddrop { display: flex; flex-direction: column; gap: calc(var(--pad) / 2); width: 100%; }
.ddrop__face { display: flex; align-items: center; justify-content: space-between; gap: calc(var(--pad) / 2); width: 100%; min-width: 0; background: var(--card); border: var(--border); padding: calc(var(--pad) / 2) calc(var(--pad) * 0.75); color: var(--text); font: inherit; font-size: var(--t-label); font-weight: 700; line-height: var(--lh); text-align: left; cursor: pointer; }
.ddrop__face:hover { background: var(--card-hover); }
.ddrop__face:focus-visible { outline: var(--selected-border); outline-offset: 0.12rem; }
.ddrop__face[aria-expanded='true'] { outline: var(--selected-border); outline-offset: 0; }   /* (open: a ring, never a heavier border) */
.ddrop__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ddrop__body { display: flex; flex-direction: column; gap: var(--pad); width: 100%; }
.ddrop__body[hidden] { display: none; }
.ddrop__body > .entry__print { display: flex; flex-direction: column; align-items: stretch; gap: var(--pad); }
.ddrop__body .btn { width: 100%; }
.ddrop__body .entry__print > .switch { align-self: flex-start; }
/* THE DESCRIPTION BOX: at the drawer's foot at all times (sticky), the panel's ground behind it and around it so what
   scrolls goes under it; the right drawer's status area's look — small, a bold word, what it is */
.drawer--left > .drawer__about { position: sticky; bottom: 0; z-index: 5; margin-top: auto; flex: 0 0 auto; gap: calc(var(--pad) / 4); background: var(--panel); box-shadow: 0 0 0 var(--pad) var(--panel); border-top: var(--border); border-radius: 0; padding: var(--pad) calc(var(--pad) / 2) 0; font-size: var(--t-small); color: var(--text2); }
.drawer__about:empty { display: none; }
.drawer__about .about__title { font-weight: 700; color: var(--text); }
.drawer__about .status__item { white-space: normal; overflow: visible; }
.drawer__about .about__text { line-height: var(--lh); }
.drawer__about .about__tasks { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.drawer[data-state='rail'] .drawer__about { display: none; }


/* ---------- (v67 — 36.0) MY TO-DO — a person's own list (todo.js) ---------- */
.todo { max-width: 52rem; }
.todo__form { display: flex; align-items: stretch; gap: var(--pad); width: 100%; }
.todo__in { flex: 1 1 auto; min-width: 0; font: inherit; font-size: var(--t-body); line-height: var(--lh); padding: var(--pad); background: var(--card); color: var(--text); border: var(--border); border-radius: var(--radius-cap); }
.todo__in::placeholder { color: var(--text2); }
.todo__in:focus-visible { outline: var(--selected-border); outline-offset: calc(var(--pad) / 4); }
.todo__add { width: auto; flex: 0 0 auto; padding-inline: calc(var(--pad) * 2); }
/* the line: two lines of words' room, or Undo's height, whichever is more — so nothing under it moves when it speaks */
.todo__line { display: flex; align-items: center; gap: var(--pad); width: 100%; font-size: var(--t-small); min-height: max(calc(2em * var(--lh)), calc(1em * var(--lh) + var(--pad) * 2 + 0.25rem)); }
.todo__said { flex: 1 1 auto; min-width: 0; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.todo__undo { margin-left: auto; }
.todo__list { display: flex; flex-direction: column; gap: calc(var(--gap) / 2); width: 100%; }
.todo__list[hidden], .todo__done[hidden] { display: none; }
.todo__item { display: flex; align-items: center; gap: var(--pad); width: 100%; min-height: 3rem; padding: 0 var(--pad); background: var(--card); color: var(--text); }
.todo__item--skel { height: 3rem; background: var(--card-hover); }
.todo__toggle { flex: 1 1 auto; min-width: 0; min-height: 2.75rem; display: flex; align-items: center; gap: var(--pad); padding: calc(var(--pad) / 3) 0; background: none; border: 0; color: inherit; font: inherit; font-size: var(--t-body); line-height: var(--lh); text-align: left; cursor: pointer; }
.todo__toggle:focus-visible { outline: var(--selected-border); outline-offset: calc(var(--pad) / 4); border-radius: var(--radius-cap); }
.todo__box { flex: 0 0 auto; width: 1.6em; height: 1.6em; display: grid; place-items: center; background: var(--raised); border: var(--border); }
.todo__tick { visibility: hidden; font-weight: 700; line-height: 1; color: var(--button-text); }
.todo__text { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.todo__item[data-done='true'] .todo__box { background: oklch(calc(var(--btn-l) * 1%) var(--btn-c) var(--btn-h)); }
.todo__item[data-done='true'] .todo__tick { visibility: visible; }
.todo__item[data-done='true'] .todo__text { text-decoration: line-through; color: var(--text2); }
.todo__off { flex: 0 0 auto; width: auto; min-height: 2.75rem; background: none; box-shadow: none; color: var(--text2); }   /* quiet: the item is what the eye goes to */
.todo__off:hover { color: var(--text); }
.todo__done { display: flex; flex-direction: column; gap: calc(var(--gap) / 2); width: 100%; }
.todo__donehead { align-self: flex-start; background: none; border: 0; padding: calc(var(--pad) / 2) 0; color: var(--text2); font: inherit; font-size: var(--t-label); font-weight: 700; cursor: pointer; text-align: left; }
.todo__donehead:focus-visible { outline: var(--selected-border); outline-offset: calc(var(--pad) / 4); }
.todo__empty, .todo__why { padding: var(--pad) 0; }

/* (v74 — 36.11) THE THREE LINES — Layout 2, the map and the PDF alike (site.js v46, task.js v68; Pete, 2026-10-22: "I really
   want this to be consistent in both map and PDF"): (1) Racking · Wiring at the left, the zoom (− · N% · + · Fit,
   zoomdock.js) at the right; (2) the location dropdowns at the left — sliding sideways where they do not fit, never cut —
   and Up at the right, always; (3) the crews (.atlas__crews / .entry__picks), one line, the picked one in its middle. Every
   control on the two lines is ONE height (--nav-h, a dropdown's), so the lines are one height whatever they hold; the PDF's
   lines are the map's own classes in the same container (.atlas__up.nav3, the viewer a container named atlas), so Racking ·
   Wiring, the zoom and Up stand to the pixel where they stand on the map. */
:root[data-layout='drawers'] .entry__view > .viewer { container: atlas / inline-size; }
.atlas__up.nav3 { display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 0; min-height: 0; width: 100%; font-size: var(--t-small); --nav-h: calc(var(--lh) * 1em + var(--pad) * 1.4 + 0.125rem); }
.atlas__up.nav3 > .nav3__lines { display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: calc(var(--pad) / 2); flex: 0 0 auto; width: 100%; min-width: 0; min-height: 0; }
.atlas__up.nav3 > .nav3__lines::after { display: none; }
.nav3 .navline { display: flex; flex-wrap: nowrap; align-items: center; gap: var(--pad); height: var(--nav-h); min-width: 0; }
.nav3 .navline__l { flex: 1 1 auto; min-width: 0; height: 100%; display: flex; align-items: center; gap: calc(var(--pad) / 2); }
.nav3 .navline__r { flex: 0 0 auto; height: 100%; display: flex; align-items: center; gap: calc(var(--pad) / 2); margin-left: auto; }
.nav3 .navline__slide { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; overscroll-behavior-x: contain; padding-block: 0.125rem; margin-block: -0.125rem; height: calc(100% + 0.25rem); }
.nav3 .navline__slide::-webkit-scrollbar { display: none; }
.nav3 .navline__slide[data-more] { -webkit-mask-image: linear-gradient(to right, oklch(0 0 0) calc(100% - 2rem), transparent); mask-image: linear-gradient(to right, oklch(0 0 0) calc(100% - 2rem), transparent); }
.nav3 .navline__slide[data-less] { -webkit-mask-image: linear-gradient(to left, oklch(0 0 0) calc(100% - 2rem), transparent); mask-image: linear-gradient(to left, oklch(0 0 0) calc(100% - 2rem), transparent); }
.nav3 .navline__slide[data-more][data-less] { -webkit-mask-image: linear-gradient(to right, transparent, oklch(0 0 0) 2rem, oklch(0 0 0) calc(100% - 2rem), transparent); mask-image: linear-gradient(to right, transparent, oklch(0 0 0) 2rem, oklch(0 0 0) calc(100% - 2rem), transparent); }
.nav3 .navline :is(.atlas__viewsat, .atlas__upat, .atlas__where, .atlas__views) { display: flex; flex: 0 0 auto; align-items: center; height: 100%; gap: calc(var(--pad) / 2); margin: 0; }
.atlas__up.nav3 .navline :is(.btn, .pick) { height: var(--nav-h); box-sizing: border-box; flex: 0 0 auto; width: auto; max-width: none; font-size: var(--t-small); line-height: var(--lh); padding-block: 0; padding-inline: calc(var(--pad) * 0.7); white-space: nowrap; }
.atlas__up.nav3 .navline .btn { display: inline-flex; align-items: center; justify-content: center; }
.atlas__up.nav3 .navline .pick { field-sizing: content; padding-inline: calc(var(--pad) / 2); }
.atlas__up.nav3 .navline .zoomdock__btn { min-width: 2.4em; padding-inline: calc(var(--pad) / 2); font-weight: 700; }
.atlas__up.nav3 .navline .zoomdock__btn[data-zoom='fit'] { padding-inline: calc(var(--pad) * 0.7); }
.atlas__up.nav3 .navline .zoomdock__pct { min-width: 4.2ch; }
.atlas__up.nav3 .atlas__views > .btn[aria-pressed='true'] { outline-offset: -0.125rem; }
.atlas__up.nav3 .navline--2 .navline__r:empty { display: none; }
.atlas__up.nav3 .atlas__upbtn > span { white-space: pre; }   /* ("Up to " keeps its space: the button lays its words out as a row) */
/* a phone under 21.5rem (a 320 screen): the zoom's buttons a little narrower, so Racking · Wiring and the four share line 1 */
@container atlas (max-width: 21.5rem) {
  .atlas__up.nav3 .navline .zoomdock__btn { min-width: 2em; padding-inline: calc(var(--pad) / 3); }
  .atlas__up.nav3 .navline .zoomdock__pct { min-width: 3.6ch; }
  .atlas__up.nav3 .navline :is(.atlas__views > .btn) { padding-inline: calc(var(--pad) / 2); }
  .nav3 .navline { gap: calc(var(--pad) / 2); }
}
/* (3) the crews: on every face and in every state in Layout 2 — the List too (a crew picked there is the map's and the PDF's) */
.atlas[data-upbar][data-face='list'] > .atlas__crews { display: block; }
/* THEN THE VIEW, THEN ITS TASKS — never over it: an open section's and an LBD's or PCS's own header (name, what is showing,
   Drawing) is the description box's and the View / Edit's; the rows or the book's page first, the tasks, the day and
   Completed under them, at every width (Pete's pick: "Under the page") */
.atlas[data-upbar] .sec__head { display: none; }
.atlas[data-upbar] .sec__body { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
.atlas[data-upbar] .sec__left, .atlas[data-upbar] .sec__entry { flex: 0 0 auto; }
.atlas[data-upbar] .lbd__head { display: none; }
.atlas[data-upbar] .lbd__body { flex-direction: column; align-items: stretch; overflow-x: hidden; overflow-y: auto; }
.atlas[data-upbar] .lbd__left { display: contents; }
.atlas[data-upbar] .lbd__entry { flex: 0 0 auto; min-height: auto; overflow: visible; }
.atlas[data-upbar] .lbd__grid { position: sticky; top: 0; flex: 0 0 auto; height: min(calc(100cqw * 11 / 17 + 0.5rem), 60cqh); min-height: 14rem; box-shadow: 0 var(--pad) 0 0 var(--panel); }
.atlas[data-upbar] .sheetview__head--bare { display: none; }
.atlas[data-upbar] .sheetview:not(.sheetview--book) > .sheetview__head { order: 2; }
.atlas[data-upbar] .sheetview__head > .sheetview__line:first-child { display: none; }
/* the left drawer's View / Edit: the view's own switches and actions, the drawer's width each */
.entry__viewtools { display: flex; flex-direction: column; align-items: stretch; gap: calc(var(--pad) / 2); width: 100%; }
.entry__viewhold { display: flex; flex-direction: column; width: 100%; }
.entry__printhold { display: contents; }   /* (the Print / Export dropdown's place in the drawer's one section) */
.entry__viewtools:empty::before { content: 'Nothing to switch in this view.'; color: var(--text2); font-size: var(--t-small); }
.entry__viewtools > .btn { width: 100%; justify-content: center; }
.entry__viewtools > .switch { align-self: flex-start; }
.zoomdock { display: flex; flex-wrap: nowrap; align-items: center; gap: calc(var(--pad) / 2); }
.zoomdock > .zoomdock__btn { flex: 0 0 auto; width: auto; justify-content: center; font-weight: 700; white-space: nowrap; }
.zoomdock > .zoomdock__btn:not([data-zoom='fit']) { min-width: 2.6em; }
.zoomdock__pct { flex: 0 0 auto; min-width: 5ch; text-align: center; font-size: var(--t-small); font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); white-space: nowrap; }
.ft__zoombar { margin-left: auto; }   /* (the picked form's zoom: at the right of the line over it, after Up) */


/* ---------- (v78 — 36.15) INVERTER REASSIGNMENTS — the official list (reassign.js) ---------- */
.reassign { max-width: 80rem; }
.reassign__what { margin: 0; max-width: 60rem; }
.reassign__bar { display: flex; align-items: center; gap: var(--pad); width: 100%; min-height: calc(1em * var(--lh) + var(--pad) * 2 + 0.25rem); }
.reassign__said { flex: 1 1 auto; min-width: 0; margin: 0; }
.reassign__csv { width: auto; flex: 0 0 auto; }
/* the table scrolls sideways in its own box on a phone; the page never does */
.reassign__box { width: 100%; overflow-x: auto; }
.reassign__table { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.reassign__table th, .reassign__table td { text-align: left; padding: calc(var(--pad) / 3) calc(var(--pad) / 2); border-bottom: var(--border); white-space: nowrap; }
.reassign__table th { font-weight: 700; color: var(--text2); }
.reassign__table td:nth-child(6), .reassign__table td:nth-child(7) { white-space: normal; min-width: 9rem; }
.reassign__code, .reassign__new { font-weight: 700; }
.reassign__table tr[data-state='done'] .reassign__new { color: var(--light-green); }
.reassign__table tr[data-state='maybe'] td:nth-child(7) { font-style: italic; }


/* ---------- (v79 — 36.19) FOLDED, A DRAWER IS SQUARES (drawers.js v21) ---------- */
/* what only a folded drawer has: the ⓘ, command over dialogue, the lights — none of it on an open drawer */
.drawer__railbtn, .drawer__railpair, .drawer__railleds { display: none; }
.drawer[data-state='rail'] { gap: calc(var(--pad) / 2); }
.drawer[data-state='rail'] .drawer__top { align-items: stretch; gap: calc(var(--pad) / 2); }
.drawer[data-state='rail'] .drawer__group { padding: 0; align-items: stretch; background: transparent; border: none; box-shadow: none; }
/* every square: the rail's width, as tall as it is wide */
.drawer[data-state='rail'] .drawer__burger,
.drawer[data-state='rail'] .doorway__logo-box,
.drawer[data-state='rail'] .drawer__railbtn { flex: 0 0 auto; width: 100%; height: auto; aspect-ratio: 1 / 1; min-width: 0; padding: 0; margin: 0; display: flex; align-items: center; justify-content: center; }
.drawer[data-state='rail'] .drawer__burger > svg { width: 55%; height: 55%; }
/* Vantage: its V over the build, in one square */
.drawer--left[data-state='rail'] .drawer__top .doorway--big .doorway__logo-box { flex-direction: column; gap: 0; padding: calc(var(--pad) / 4); }
.drawer--left[data-state='rail'] .drawer__top .lockup { --lk: calc(var(--rail-w) * 0.22); }
.drawer--left[data-state='rail'] .drawer__build { font-size: calc(var(--t-small) * 0.85); line-height: 1.1; }
/* Egan: its logo fitted inside its square */
.drawer[data-state='rail'] .doorway--logo .doorway__logo-box { padding: 0.125rem; }
.drawer[data-state='rail'] .doorway__logo { width: 94%; height: auto; max-height: 94%; object-fit: contain; }
.drawer[data-state='rail'] .doorway { width: 100%; }
/* the person: their mark in the middle of its square — the square the logos' own (the card, its border) */
.drawer[data-state='rail'] [data-doorway='user'] .doorway__logo-box { justify-content: center; background: var(--card); border: var(--border); overflow: hidden; }
.drawer[data-state='rail'] [data-doorway='user'] .user-id { width: 100%; height: 100%; gap: 0; justify-content: center; }
.drawer[data-state='rail'] .user-mark { height: 72%; width: 72%; font-size: var(--t-small); }
/* the theme is the open drawer's alone */
.drawer[data-state='rail'] .theme__face { display: none; }
/* the ⓘ — the description box, folded — at the left drawer's foot */
.drawer[data-state='rail'] .drawer__railbtn { display: flex; }
.drawer[data-state='rail'] .drawer__railbtn > svg { width: 58%; height: 58%; display: block; }
.drawer--left[data-state='rail'] .drawer__railinfo { margin-top: auto; }
/* command over dialogue: two squares, one rectangle — the line between them is the one border */
.drawer[data-state='rail'] .drawer__railpair { display: flex; flex-direction: column; width: 100%; flex: 0 0 auto; }
.drawer[data-state='rail'] .drawer__railpair > .drawer__railcmd { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.drawer[data-state='rail'] .drawer__railpair > .drawer__railtalk { border-top-left-radius: 0; border-top-right-radius: 0; border-top: none; }
/* the lights, one over the other, where the status area is: at the right drawer's foot */
.drawer[data-state='rail'] .drawer__railleds { display: flex; flex-direction: column; align-items: center; gap: calc(var(--pad) / 2); width: 100%; flex: 0 0 auto; margin-top: auto; padding: calc(var(--pad) / 2) 0; background: var(--card); border: var(--border); cursor: pointer; font-size: var(--t-body); }
.drawer[data-state='rail'] .drawer__railleds > .dot { margin: 0; }
/* a working line's dots (dialogue.js v21): their own width, so nothing beside them moves as they count */
.dialogue__dots { display: inline-block; width: 1.6em; text-align: left; white-space: pre; }
.dialogue__work { font-size: var(--t-label); white-space: pre-wrap; font-weight: 700; }
.dialogue__work[hidden] { display: none; }

