/* Shared chrome for the workspace applications.
 *
 * Loaded after each application's own <style> block, so it settles the two
 * things those blocks each decided separately.
 *
 * 1. Height. Docs, Sheets and Slides lay their shell out as a flex column on a
 *    body pinned to the viewport. That is right for an application and was
 *    right until the reference material (the questions, the related tools, the
 *    licence note) was added as further children of the same column. Those
 *    blocks are about five hundred pixels tall, the shell had eight hundred to
 *    give, and the working area is the only flexible item in the column, so it
 *    was squeezed to nothing. Opening Docs gave you a toolbar and a list of
 *    questions with no document under it.
 *
 *    The fix is to stop pinning the body to the viewport. The application still
 *    fills the window on load, because the working area keeps a viewport-height
 *    floor, and the reference material sits below it where scrolling reaches it.
 *
 * 2. Motion. One curve and one duration, honoured everywhere, and none of it
 *    for anyone who has asked their system for less movement.
 */

:root {
  /* Decelerating, slightly overshoot-free. Movement should look like something
     settling rather than something stopping. */
  --app-ease: cubic-bezier(0.32, 0.72, 0, 1);
  --app-duration: 180ms;
}

/* --- 1. The working area gets its height back ---------------------------- */

/* dvh, not vh, and the pair rather than one of them.
   On iOS Safari 100vh is the *large* viewport: the height the page would have
   if the URL bar were hidden, which it is not when you arrive. So a floor of
   100vh on a page with nothing below the fold still gives it eighty pixels of
   nothing to scroll to, and the page rubber-bands when you flick it. 100dvh is
   the height you can actually see. vh stays first so a browser that does not
   know dvh still gets a floor rather than none. */
body {
  height: auto;
  min-height: 100vh;
  min-height: 100dvh;
}

.workspace-stage {
  flex: 1 0 auto;
  /* 160px is the header and toolbar above it. The floor matters more than its
     precision: it stops the reference material below from claiming the space. */
  min-height: calc(100vh - 160px);
  min-height: calc(100dvh - 160px);
}

/* --- 2. The reference material reads as a footer, not as part of the app -- */

.os-faq,
.os-rel {
  flex: 0 0 auto;
  width: 100%;
  box-sizing: border-box;
}

/* --- 3. Motion ----------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- 4. One control scale ------------------------------------------------
 *
 * Measured across the six applications before this was written: nine different
 * control heights (20, 21, 24, 26, 28, 29, 30, 32, 34px) and seven different
 * corner radii (0, 4, 5, 6, 7, 8px and 50%). Each application had picked its
 * own, which is why they looked like six programs rather than one.
 *
 * One height and one radius for anything that sits in a toolbar. min-height
 * rather than height, so a control that genuinely needs to be taller still can
 * be, and so nothing that was already laid out gets clipped.
 */

:root {
  --ctl-h: 30px;
  --ctl-r: 6px;
  --panel-r: 10px;
}

[class*="toolbar"] button,
[class*="toolbar"] select,
[class*="toolbar"] input[type="text"],
[class*="toolbar"] input[type="number"] {
  min-height: var(--ctl-h);
  border-radius: var(--ctl-r);
  box-sizing: border-box;
}

/* Round things that are meant to be round stay round: colour swatches, and
   anything a stylesheet has already named as a circle or an avatar. */
[class*="toolbar"] button[class*="swatch"],
[class*="toolbar"] [class*="circle"],
[class*="toolbar"] [class*="avatar"] {
  border-radius: 50%;
}

/* A finger is not a mouse pointer. Forty-four points is the smallest target
   Apple's guidelines will accept, and a dense toolbar is exactly where a
   too-small target costs you. */
@media (pointer: coarse) {
  [class*="toolbar"] button,
  [class*="toolbar"] select {
    min-height: 44px;
    min-width: 44px;
  }
}

/* --- 5. One header --------------------------------------------------------
 *
 * Docs and Notes carry the same header: the Workspace mark at the left, the
 * name of what is open with a line under it saying where it is saved, and the
 * few actions that matter as pills on the right. Sheets and Slides each had
 * their own, smaller and in another typeface, so the four applications read
 * as four programs. This is that header once, in the measurements of the
 * Notes header, for any application that wants it.
 *
 * The saved line is coloured by its data-state rather than by inline styles
 * from the application, so the thirteen colourways decide what "saving" and
 * "full" look like, not a hard-coded hex.
 */

.app-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 18px;
  background: var(--paper-raised);
  border-bottom: 1px solid var(--rule);
  flex-shrink: 0;
}
.app-head-brand { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1 1 auto; }
.app-logo {
  display: flex; flex: none; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; margin: -5px; text-decoration: none;
}
.app-logo svg { width: 34px; height: 34px; display: block; }
.app-head-titles { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.app-head-title {
  width: 100%; max-width: 520px; min-width: 0;
  font-family: inherit; font-size: var(--text-lg); font-weight: 600; line-height: 1.25; color: var(--ink);
  background: transparent; border: 1px solid transparent; border-radius: 6px;
  padding: 1px 6px; margin-left: -7px; outline: none; text-overflow: ellipsis;
}
.app-head-title:hover { border-color: var(--rule); background: var(--paper-inset); }
.app-head-title:focus { border-color: var(--accent); background: var(--paper); }
/* min-width:0 and an ellipsis. This is a flex item whose automatic minimum
   is its whole sentence - "New. Saved in this browser as you type" - and
   on a 320px phone that ran past the right edge of a header that cannot
   scroll. It is a status line, so shortening it costs nothing; being off
   the screen behind overflow-x:hidden costs the whole message. */
.app-head-status { margin: 2px 0 0; font-size: var(--text-2xs); color: var(--ink-soft);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-head-status::before {
  content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--good); margin-right: 6px; vertical-align: 1px;
}
.app-head-status[data-state="saving"]::before { background: var(--ink-faint); }
.app-head-status[data-state="full"] { color: var(--danger); font-weight: 600; }
.app-head-status[data-state="full"]::before { background: var(--danger); }
.app-head-actions { display: flex; align-items: center; gap: 8px; flex: none; flex-wrap: wrap; justify-content: flex-end; }
.app-btn {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px;
  padding: 6px 14px; border-radius: 20px; border: 1px solid var(--rule);
  background: var(--paper-raised); color: var(--ink);
  font-family: inherit; font-size: var(--text-xs); font-weight: 600; line-height: 1.2;
  cursor: pointer; text-decoration: none; white-space: nowrap;
}
.app-btn:hover { background: var(--paper-inset); border-color: var(--accent); color: var(--accent-strong); }
.app-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--paper-raised); }
.app-btn.primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); color: var(--paper-raised); }
.app-btn svg { width: 14px; height: 14px; flex: none; }

/* A phone: the mark and the name on one row, the actions on a second row
   that scrolls sideways, as the Notes header does. */
@media (max-width: 640px) {
  .app-head { flex-wrap: wrap; padding: 8px 12px; gap: 8px 12px; }
  .app-head-brand { flex: 1 1 100%; }
  .app-head-titles { flex-direction: row; align-items: baseline; gap: 10px; }
  .app-head-title { flex: 1 1 auto; width: auto; max-width: none; font-size: calc(17px * var(--text-scale, 1)); }
  /* flex:0 1 auto, not flex:none. On a phone the title and the status share
     one row, and flex:none meant the status kept its full sentence - "New.
     Saved in this browser as you type" - whatever the room. On a 320px
     screen it ended 12px past the right edge of a header that does not
     scroll, so the end of the message was simply gone. Now it shrinks and
     the ellipsis above does the rest; the title, which is the thing worth
     reading in full, still takes the space first. */
  .app-head-status { flex: 0 1 auto; white-space: nowrap; margin: 0; }
  .app-head-actions {
    flex: 1 1 100%; justify-content: flex-start; flex-wrap: nowrap;
    overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .app-head-actions::-webkit-scrollbar { display: none; }
}
@media (pointer: coarse) {
  .app-btn, .app-head-title { min-height: 44px; }
}

/* --- 6. One menu row -------------------------------------------------------
 *
 * Under the header, a row of named tools, as Notes has: flat items that
 * light up when they are on, scrolling sideways on a phone rather than
 * wrapping into a wall. A separator and a spring are the only furniture.
 */
.app-menu {
  display: flex; align-items: center; gap: 2px;
  padding: 4px 12px; background: var(--paper-raised); border-bottom: 1px solid var(--rule);
  overflow-x: auto; scrollbar-width: none; flex-shrink: 0;
}
.app-menu::-webkit-scrollbar { display: none; }
.app-mi {
  display: inline-flex; align-items: center; gap: 6px; flex: none; min-height: 32px;
  padding: 4px 10px; border: 0; border-radius: 6px; background: transparent;
  color: var(--ink-soft); font-family: inherit; font-size: calc(13.5px * var(--text-scale, 1)); font-weight: 500; cursor: pointer; white-space: nowrap;
}
.app-mi:hover { background: var(--paper-inset); color: var(--ink); }
.app-mi.on { background: var(--accent-soft); color: var(--accent-strong); font-weight: 600; }
.app-mi[disabled] { opacity: 0.45; cursor: default; }
.app-mi svg { width: 15px; height: 15px; flex: none; }
.app-sep { display: inline-block; width: 1px; height: 22px; margin: 0 6px; background: var(--rule); flex: none; }
.app-grow { flex: 1 1 auto; }
@media (pointer: coarse) { .app-mi { min-height: 44px; min-width: 44px; justify-content: center; } }

/* A document with changes that have not been saved yet. */
.app-head-status[data-state="dirty"]::before { background: var(--warn, #c9a227); }

/* 3. Docs, as it opens on a phone. The page used to be laid out the width of
 *    the window, in the site's webfonts, and then moved onto its sheet,
 *    zoomed to fit, and reset in the document's own faces when the deferred
 *    scripts arrived two and a half seconds later: a layout shift of 0.195.
 *    Now the zoom is worked out in the head (docs-fit.js) and handed over as
 *    --docs-fit; the sheet is reserved at what docs-page.js and
 *    docs-sheets.js set for a new document (Letter, Normal margins, one page
 *    tall), and their inline values replace these; and docs.html's :root
 *    names the Obscura theme's system faces, which docs-page.js sets too
 *    and which never swap. docs-app-test.mjs measures it on a slow phone. */
@media screen {
  .doc-stack { zoom: var(--docs-fit, 1); width: 816px; }
  .doc-paper { padding: 96px; min-height: 1056px; }
}

/* --- 7. A phone: the work under one bar ------------------------------------
 *
 * The owner opened Docs on an iPhone and the bars took a third of the screen
 * before the page began. On a phone each application here keeps its own bar
 * and one row of controls, and everything else folds away until it is asked
 * for. phone-chrome-test.mjs measures it.
 */

/* Sheets. A phone has room for the grid or the ribbon, not both: the bar,
   the row of tabs and the formula bar are the chrome, and a tab opens its
   panel over the grid until a command is run or the grid is touched, as
   Docs does (sheets-shell.js). Under the tabs the ribbon took a hundred and
   five pixels more and the grid began a third of the way down. */
@media (max-width: 599px) {
  .sh-ribbon { position: relative; border-top: 0; }
  .sh-ribbon:not(.is-peek) .sh-panel { display: none; }
  .sh-ribbon.is-peek .sh-panel:not([hidden]) {
    position: absolute; left: 0; right: 0; top: 0; z-index: 60;
    background: var(--sh-ribbon); border-bottom: 1px solid var(--sh-ribbon-rule);
    box-shadow: 0 8px 20px rgba(0, 0, 0, .18);
  }
}

/* Drive. The bar, the folder's name and the filters are three rows on a
   phone, so each is no taller than its controls: together they took a fifth
   of the screen above the first file. */
@media (max-width: 768px) {
  .dr { grid-template-rows: 52px minmax(0, 1fr); }
  .dr-top { padding: 4px 8px 4px 4px; }
  .dr-search { height: 44px; }
  .dr-head { min-height: 48px; padding: 2px 8px 0 4px; }
  .dr-bar { min-height: 0; padding: 2px 8px 4px; }
}

/* 4. Docs on a phone opens in Web Layout (docs-fit.js, docs-sheets.js):
 *    the same as docs.html's body.doc-view-web from the first paint, and
 *    on a phone the margins are the screen's, not the page's, or an inch
 *    either side would leave half the width for text. */
html.docs-phone .doc-sheets { display: none; }
html.docs-phone .doc-stack { width: auto !important; }
html.docs-phone .ruler-container { display: none; }
html.docs-phone .doc-paper { background: var(--page-bg); box-shadow: var(--page-shadow); }
/* In Web Layout on a phone the text runs to the foot of the screen, so the
   privacy badge would sit on it; there, as in Sheets and Plan, it is not
   shown (the request list is still under Help). */
@media (max-width: 599px) {
  html.docs-phone #ppBadge { display: none; }
  html.docs-phone .doc-paper, body.doc-view-web .doc-paper { padding: 24px 20px 48px !important; min-height: calc(100dvh - 220px) !important; }
}

/* 5. Sheets on a phone: one bar, as the paid applications have. The
 *    workbook's name comes straight after the way home, wide enough to be
 *    read (it was cut to "Operating Bud" behind the buttons once, and a
 *    line of its own pushed the grid too far down), then Undo and Redo;
 *    Save, Open in and the folder are along the same row, which scrolls
 *    sideways within itself behind the chevron (details.js). */
@media (max-width: 760px) {
  body.sheets-app .sh-titlebar { flex-wrap: nowrap; gap: 0; padding: 0 4px; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; }
  body.sheets-app .sh-titlebar::-webkit-scrollbar { display: none; }
  body.sheets-app .sh-titlebar > * { flex: none; }
  body.sheets-app .sh-title { display: contents; }
  body.sheets-app .sh-title input { order: 1; flex: none; width: calc(100vw - 166px); min-width: 0; padding: 3px 4px; font-weight: 500; text-align: left; text-overflow: ellipsis; }
  body.sheets-app .sh-qat { order: 2; }
  body.sheets-app .sh-qat [data-cmd="undo"], body.sheets-app .sh-qat [data-cmd="redo"] { order: -1; }
  body.sheets-app .sh-titlebar .fw-chip { order: 3; margin: 0; }
  /* In a row that scrolls, rings are drawn inside, where they are not cut. */
  body.sheets-app .sh-titlebar :focus-visible, .sh-bs-nav :focus-visible { outline-offset: -2px; }
}
/* A chevron on a coloured bar is in the bar's own ink. */
:is(body.sheets-app .sh-titlebar, .sh-bs-nav) > .row-cue { color: inherit; border-color: color-mix(in srgb, currentColor 30%, transparent); }

/* 6. Calendar with a finger: every control is a thumb wide (theme.css), so
 *    the side panel is wide enough for seven of them across, or Saturday
 *    falls off the edge of the date picker. */
@media (pointer: coarse) {
  body.calendar-app .ca-side { box-sizing: border-box; width: min(340px, calc(100vw - 16px)); }
  body.calendar-app .mini { padding: 0; }
}

/* 7. Docs in dark mode. The pages stay paper, as Word's and Google Docs'
 *    do, so what is on the screen is what prints and a colour is judged
 *    against white; View, Dark page (docs-sheets.js) draws them dark as
 *    well. Only the pages and the ruler over them take paper's colours:
 *    the window round them stays dark. */
:root[data-theme="dark"]:not(.docs-dark-page) :is(.doc-stack, .ruler-track) {
  color-scheme: light;
  --page-bg: var(--print-paper);
  --page-shadow: 0 0 0 1px rgba(0, 0, 0, .3), 0 6px 20px rgba(0, 0, 0, .55);
  --paper: var(--print-paper);
  --paper-raised: var(--print-paper);
  --paper-inset: var(--print-inset);
  --rule: var(--print-rule);
  --rule-strong: var(--print-rule-strong);
  --ink: var(--print-ink);
  --ink-soft: var(--print-ink-soft);
  --ink-mid: var(--print-ink-soft);
  --ink-faint: var(--print-ink-faint);
  --accent: var(--print-accent);
  --accent-strong: var(--print-accent-strong);
  --accent-soft: var(--print-accent-soft);
  --doc-heading: var(--print-accent-strong);
  --on-accent: var(--print-paper);
  --focus: var(--print-accent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not(.docs-dark-page) :is(.doc-stack, .ruler-track) {
    color-scheme: light;
    --page-bg: var(--print-paper);
    --page-shadow: 0 0 0 1px rgba(0, 0, 0, .3), 0 6px 20px rgba(0, 0, 0, .55);
    --paper: var(--print-paper);
    --paper-raised: var(--print-paper);
    --paper-inset: var(--print-inset);
    --rule: var(--print-rule);
    --rule-strong: var(--print-rule-strong);
    --ink: var(--print-ink);
    --ink-soft: var(--print-ink-soft);
    --ink-mid: var(--print-ink-soft);
    --ink-faint: var(--print-ink-faint);
    --accent: var(--print-accent);
    --accent-strong: var(--print-accent-strong);
    --accent-soft: var(--print-accent-soft);
    --doc-heading: var(--print-accent-strong);
    --on-accent: var(--print-paper);
    --focus: var(--print-accent);
  }
}

/* 8. Docs' title bar in dark mode is the raised dark of the other
 *    applications' bars (Slides, Plan), not a band of the pale dark-mode
 *    accent that no other window has. */
:root[data-theme="dark"] .docs-titlebar { background: var(--paper-raised); color: var(--ink); border-bottom: 1px solid var(--rule); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .docs-titlebar { background: var(--paper-raised); color: var(--ink); border-bottom: 1px solid var(--rule); }
}

/* 9. Sheets: slicers, the filter view bar, and the What-If and Solver
 *    dialogs (sheets-data.js, sheets-tools.js). */
body.sheets-app .sh-slicer { position: absolute; z-index: 23; display: flex; flex-direction: column; background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); box-shadow: 0 1px 3px rgba(0, 0, 0, .15); outline: none; overflow: hidden; }
body.sheets-app .sh-slicer:focus-visible, body.sheets-app .sh-slicer:focus-within { border-color: var(--sheet-green); box-shadow: 0 0 0 1px var(--sheet-green); }
body.sheets-app .sh-slicer-head { display: flex; align-items: center; gap: 2px; min-height: 32px; padding: 0 4px 0 10px; border-bottom: 1px solid var(--rule); font-weight: 600; cursor: move; }
body.sheets-app .sh-slicer-head > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.sheets-app .sh-slicer-tool { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: 1px solid transparent; border-radius: var(--radius-sm); background: none; color: var(--ink-soft); cursor: pointer; }
body.sheets-app .sh-slicer-tool svg { width: 16px; height: 16px; }
body.sheets-app .sh-slicer-tool:hover { background: var(--sh-hover); }
body.sheets-app .sh-slicer-tool[aria-pressed="true"] { border-color: var(--sheet-green); color: var(--sheet-green); }
body.sheets-app .sh-slicer-tool:disabled { opacity: .4; cursor: default; }
body.sheets-app .sh-slicer-items { flex: 1; overflow: auto; padding: 6px; display: flex; flex-direction: column; gap: 4px; }
body.sheets-app .sh-slicer-item { min-height: 28px; padding: 2px 8px; border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); background: var(--paper); color: var(--ink-soft); text-align: left; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.sheets-app .sh-slicer-item[aria-pressed="true"] { background: var(--sh-pressed); border-color: var(--sheet-green); color: var(--ink); }
body.sheets-app .sh-slicer-item:focus-visible, body.sheets-app .sh-slicer-tool:focus-visible { outline: 2px solid var(--sheet-green); outline-offset: 1px; }
body.sheets-app .sh-slicer-gone { margin: 8px 10px; color: var(--ink-soft); }
body.sheets-app .sh-fv-bar { display: flex; align-items: center; gap: 8px; flex: none; max-width: 45%; margin-left: 6px; padding: 0 2px 0 10px; border-radius: var(--radius-sm); background: var(--sh-pressed); color: var(--ink); white-space: nowrap; }
body.sheets-app .sh-fv-bar[hidden] { display: none; }
body.sheets-app .sh-fv-label { color: var(--ink-soft); }
body.sheets-app .sh-fv-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
body.sheets-app .sh-fv-bar .sh-b { min-width: 0; min-height: 22px; padding: 0 10px; }
@media (max-width: 760px) { body.sheets-app .sh-fv-label { display: none; } }
dialog.sh-dlg .sh-facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 14px; margin: 0 0 6px; font-variant-numeric: tabular-nums; }
dialog.sh-dlg .sh-facts dt { color: var(--ink-soft); }
dialog.sh-dlg .sh-facts dd { margin: 0; }
dialog.sh-dlg .sh-pre { white-space: pre-line; }
dialog.sh-dlg .sh-sc { display: grid; grid-template-columns: 1fr max-content; gap: 12px; align-items: start; }
dialog.sh-dlg .sh-sc-acts { display: flex; flex-direction: column; gap: 6px; padding-top: 18px; }
dialog.sh-dlg .sh-sc-values { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 0 10px; }
dialog.sh-dlg .sh-sol-goal { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; }
dialog.sh-dlg .sh-sol-goal input[type="text"] { width: 110px; min-height: 28px; padding: 3px 6px; border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); background: var(--paper-raised); color: var(--ink); }
dialog.sh-dlg .sh-sol-list { height: 110px; margin-bottom: 8px; }
dialog.sh-dlg .sh-sol-add { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
dialog.sh-dlg .sh-sol-add input, dialog.sh-dlg .sh-sol-add select { min-height: 28px; padding: 3px 6px; border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); background: var(--paper-raised); color: var(--ink); }
dialog.sh-dlg .sh-sol-add input { width: 96px; }
@media (pointer: coarse) {
  body.sheets-app .sh-slicer-item, body.sheets-app .sh-slicer-tool { min-height: 44px; }
  body.sheets-app .sh-slicer-tool { width: 44px; }
}
@media (max-width: 600px) {
  dialog.sh-dlg .sh-sc { grid-template-columns: 1fr; }
  dialog.sh-dlg .sh-sc-acts { flex-direction: row; flex-wrap: wrap; padding-top: 0; }
}
