/*
 * DocGen portal - the hand-written layer on top of Peacock.
 *
 * Peacock (styles.css + tokens-import/fig-tokens.css) supplies fonts, the 592-token
 * colour/gradient system and nothing else. This file is the component layer the nine
 * screens in docs/design/ are built from, plus the overrides that make Wagtail's own
 * chrome match. It is deliberately the ONLY hand-written stylesheet: the handoff scoped
 * this as a theme override, not a parallel component set.
 *
 * RULES THIS FILE FOLLOWS, from docs/design/design_handoff_docgen_peacock/README.md:
 *
 *   * No hard-coded colours. Every colour is var(--color-*) or a var(--gradient-*).
 *     The ONE exception is `.dg-paper` and its children at the bottom of this file:
 *     those depict PRINTED PAPER, which does not follow the UI theme, and the five
 *     literals there are named in the handoff as deliberate.
 *   * Spacing/radii/type sizes are literal px, because the prototype is inline-styled
 *     in px and the instruction is to recreate it pixel-for-pixel. Peacock's spacing
 *     tokens are unitless (calc(var(--spacing-4) * 1px)) and go unused here for that
 *     reason - the prototype never used them either.
 *   * Light/dark is Peacock's own token scopes. There is no second palette in this
 *     file and there must never be one: `:root[data-theme="light"]` resolves the light
 *     values, bare `:root` the dark ones, so every rule below is theme-agnostic.
 *
 * Class prefix is `dg-`. Buttons keep the design system's own `.lb-btn` name, because
 * the handoff says to reproduce that component rather than invent a new class.
 */

/* ── Base ──────────────────────────────────────────────────────────────────── */

/* border-box on everything, and this is a bug fix rather than a preference.
 *
 * Peacock ships tokens and fonts and no reset, and Django templates get none either - so the
 * CSS default of `content-box` applied. Every element combining `width: 100%` with padding
 * was therefore WIDER than its container by the size of its own padding, and the overflow
 * hung off the right-hand side. It showed up as the sidebar's active dot and approvals count
 * sitting against the border: `.dg-nav-item` was 224px of content plus 26px of padding inside
 * a 224px column, so its right padding was simply off the edge. Increasing that padding made
 * it worse, not better.
 *
 * Wagtail's own admin CSS resets this, which is why the screens embedded in the admin looked
 * right and the standalone shell did not.
 */
body.dg, body.dg *, body.dg *::before, body.dg *::after { box-sizing: border-box; }

/* `hidden` has to beat a component's own `display`, and it did not.
 *
 * The UA stylesheet's `[hidden] { display: none }` is specificity 0,0,1,0 and loses to any
 * class rule that sets `display` - so three elements the editor toggles with the attribute
 * stayed on screen: the rich-text surface (`.dg-surface` is `display: flex`), the toolbar,
 * and the preview iframe (`.dg-pdf-frame` is `display: block`). The visible results were a
 * document showing BOTH body surfaces at once with AsciiDoc source rendered as prose in the
 * rich one, a rich-text toolbar above a plain-source textarea, and an empty white A4-shaped
 * frame occupying the whole preview column before anything had been rendered.
 *
 * `!important` rather than per-component `[hidden]` rules: every future `hidden` toggle
 * inherits the fix, and there is no case where something is marked hidden and meant to show.
 */
[hidden] { display: none !important; }

body.dg {
  margin: 0;
  background: var(--color-surface-sunken);
  color: var(--color-text-primary);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
}

/* Scoped away from buttons on purpose. `body.dg a` is specificity 0,0,2,1 and `.lb-btn` is
   0,0,1,0, so the link colour used to win on every <a class="lb-btn"> - and in the light
   theme --color-text-link resolves to rgb(92,97,212), which is EXACTLY the solid button's
   own background. The result was a button with invisible text. `:not()` keeps the link rule
   from ever applying to something styled as a button. */
body.dg a:not([class*="lb-btn"]):not([class*="dg-nav-item"]) {
  color: var(--color-text-link); text-decoration: none;
}
body.dg a:not([class*="lb-btn"]):not([class*="dg-nav-item"]):hover {
  color: var(--color-text-link-hover);
}
body.dg a { text-decoration: none; }
body.dg input, body.dg select, body.dg textarea, body.dg button { font-family: var(--font-sans); }

.dg h1, .dg h2, .dg h3, .dg h4 { font-family: var(--font-display); color: var(--color-text-heading); margin: 0; }
.dg-mono { font-family: var(--font-mono); }

/* Visible focus, on every interactive thing. The prototype does not draw focus rings -
   it is a static mock - but shipping it without them would make the whole portal
   keyboard-hostile, and every screen here is an admin surface someone tabs through. */
.dg :focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 2px;
}

.dg-sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The skip link: off-screen until keyboard focus reaches it, then a small pill over the
   top-left corner. The sidebar stands between the top of the tab order and the content
   on every screen; this is the way past it. */
.dg-skip {
  position: absolute;
  left: -9999px;
  top: calc(var(--spacing-2) * 1px);
  z-index: 100;
  padding: calc(var(--spacing-2) * 1px) calc(var(--spacing-4) * 1px);
  border-radius: 8px;
  background: var(--color-surface-default);
  color: var(--color-text-link);
  border: 1px solid var(--color-border-focus);
}
.dg-skip:focus-visible { left: calc(var(--spacing-2) * 1px); }

/* ── App shell ─────────────────────────────────────────────────────────────── */

.dg-shell { min-height: 100vh; display: flex; align-items: stretch; }

.dg-sidebar {
  width: 248px; flex: none;
  display: flex; flex-direction: column;
  background: var(--color-surface-default);
  border-right: 1px solid var(--color-border-primary);
}

.dg-brand { display: flex; align-items: center; gap: 10px; padding: 20px 20px 18px; }
.dg-brand img { width: 24px; height: 24px; display: block; }
.dg-brand-name {
  font-family: var(--font-display); font-weight: 600; font-size: 17px;
  color: var(--color-text-heading); letter-spacing: -0.01em;
}

.dg-nav { display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; }
.dg-nav-item {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  /* The handoff's 10px 12px, which only works with the border-box reset above - without it
     this padding lands outside the sidebar. */
  width: 100%; padding: 10px 12px;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--color-text-secondary);
  font-size: 15px; font-weight: 500; text-align: left; cursor: pointer;
  text-decoration: none;
}
.dg-nav-item:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); }
.dg-nav-item svg { flex: none; }
.dg-nav-item > span:first-of-type { flex: 1; }

/* Active marker: a 6px gradient dot at the right end. Not a background change - the
   handoff is specific, and a filled row would fight the hover state. */
/* Both of these are the prototype's values EXACTLY. They were briefly not: I added a margin
 * to the dot, and a border plus a line-height to the count, on the theory that the pill was
 * invisible in the light theme. It is not - --color-status-warning-bg resolves to
 * rgb(255,245,235) against rgb(138,79,15) text, which is a perfectly legible warm pill. That
 * was a wrong conclusion drawn from a scaled screenshot, and the "fix" was a divergence from a
 * design specified as pixel-for-pixel. Do not re-add either.
 *
 * `flex: none` is the one addition, and it is not visual: it stops a 6px dot or a small pill
 * being squashed by the flex-shrink default when a long nav label leaves no room. */
.dg-nav-dot {
  width: 6px; height: 6px; border-radius: 9999px;
  background: var(--gradient-declivity-2); flex: none;
}
.dg-nav-count {
  padding: 1px 7px; border-radius: 9999px;
  background: var(--color-status-warning-bg); color: var(--color-status-warning-text);
  font-size: 12px; font-weight: 600; flex: none;
}

.dg-spacer { flex: 1; }

.dg-user {
  padding: 14px 16px; border-top: 1px solid var(--color-border-muted);
  display: flex; flex-direction: column; gap: 10px;
}
.dg-user-row { display: flex; align-items: center; gap: 10px; }
.dg-avatar {
  display: grid; place-items: center; width: 30px; height: 30px; flex: none;
  border-radius: 9999px; background: var(--gradient-kepler-51);
  color: var(--color-text-on-brand); font-size: 12px; font-weight: 600;
}
.dg-user-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.dg-user-name {
  font-size: 13px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dg-user-role { font-size: 12px; color: var(--color-text-subtle); }
.dg-user-actions { display: flex; gap: 8px; }

/* Target the BUTTON, not the form. Each control is wrapped in a <form> so it can POST -
   the theme toggle and sign-out both change state - and `.dg-user-actions > *` therefore
   styled the invisible wrapper while the buttons kept the browser's default chrome. Which
   is exactly how they looked: two grey OS buttons in a Peacock sidebar. */
.dg-user-actions form { flex: 1; display: flex; }
.dg-user-actions button,
.dg-user-actions > a {
  flex: 1; padding: 7px 10px; border: 0; border-radius: 8px;
  background: var(--color-surface-sunken); color: var(--color-text-secondary);
  font-family: var(--font-sans); font-size: 13px; font-weight: 500;
  cursor: pointer; text-align: center;
}
.dg-user-actions button:hover,
.dg-user-actions > a:hover {
  background: var(--color-surface-muted); color: var(--color-text-primary);
}

.dg-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* ── Headers ───────────────────────────────────────────────────────────────── */

.dg-header {
  display: flex; align-items: flex-end; gap: 24px;
  padding: 28px 40px 20px;
  background: var(--color-surface-default);
  border-bottom: 1px solid var(--color-border-primary);
}
.dg-header-text { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.dg-header h1 { font-size: 26px; font-weight: 600; }
.dg-header p { margin: 0; font-size: 14px; color: var(--color-text-subtle); }

/* Sub-screens: tighter, and prefixed by a back button. */
.dg-header--sub { align-items: center; padding: 18px 40px; }
.dg-header--sub h1 { font-size: 20px; }

.dg-back {
  display: grid; place-items: center; width: 32px; height: 32px; flex: none;
  border: 0; border-radius: 8px; background: var(--color-surface-sunken);
  color: var(--color-text-secondary); cursor: pointer;
}
.dg-back:hover { color: var(--color-text-primary); }

.dg-meta { font-size: 13px; color: var(--color-text-subtle); }
.dg-content { padding: 24px 40px 48px; display: flex; flex-direction: column; gap: 20px; }

/* ── Buttons: the design system's .lb-btn, reproduced ──────────────────────── */
/*
 * Reproduced rather than imported: Peacock ships Button as a React component in
 * _ds_bundle.js, and this portal has no build step and no React - which is an
 * invariant, not an accident. The handoff explicitly permits reproducing the CSS
 * exactly, so these values come from it: Roboto Slab 600, 8px radius, denim-1000
 * solid, and 2px INSET SHADOW standing in for a border rather than a real border.
 *
 * The inset-shadow detail matters: a real border would change the box size and
 * misalign a solid button next to an outline one.
 */
.lb-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 18px;
  border: 0; border-radius: 8px;
  background: var(--denim-1000); color: var(--color-text-on-brand);
  font-family: var(--font-display); font-weight: 600; font-size: 16px;
  line-height: 1.2; cursor: pointer; text-decoration: none;
  transition: background .3s ease-in-out, box-shadow .3s ease-in-out, color .3s ease-in-out;
}
.lb-btn:hover { background: var(--denim-1100); color: var(--color-text-on-brand); }
.lb-btn:active { background: var(--denim-1200); }
.lb-btn[disabled], .lb-btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }

.lb-btn--outline {
  background: transparent; color: var(--color-text-secondary);
  box-shadow: inset 0 0 0 2px var(--color-border-primary);
}
.lb-btn--outline:hover {
  background: var(--color-surface-sunken); color: var(--color-text-primary);
}

/* Destructive, and outline-only on purpose: "Send back" and "Remove" must not compete
   visually with the primary action on the same row. */
.lb-btn--danger {
  background: transparent; color: var(--color-status-error-text);
  box-shadow: inset 0 0 0 2px var(--color-status-error-border);
}
.lb-btn--danger:hover { background: var(--color-status-error-bg); color: var(--color-status-error-text); }

.lb-btn--s { padding: 6px 12px; font-size: 13px; }
.lb-btn--l { padding: 12px 16px; font-size: 16px; }
.lb-btn--block { width: 100%; }

/* A text-weight action, for "Nudge" / "Open PDF" links in a card row. */
.dg-link-action { font-size: 14px; font-weight: 600; background: none; border: 0; padding: 0;
  color: var(--color-text-link); cursor: pointer; font-family: var(--font-sans); }
.dg-link-action:hover { color: var(--color-text-link-hover); }

/* ── Badges ────────────────────────────────────────────────────────────────── */
/*
 * One component, six tones, and every one carries WORDS - the handoff is explicit that
 * colour alone is never the signal. The tone is the caller's choice of modifier; the
 * text comes from the status vocabulary table in the handoff.
 */
.dg-badge {
  display: inline-block; padding: 2px 9px; border-radius: 9999px;
  font-size: 12px; font-weight: 600; white-space: nowrap; border: 1px solid transparent;
}
.dg-badge--neutral {
  background: var(--color-surface-sunken); color: var(--color-text-subtle);
  border-color: var(--color-border-primary);
}
.dg-badge--info {
  background: var(--color-status-info-bg); color: var(--color-status-info-text);
  border-color: var(--color-status-info-border);
}
.dg-badge--success {
  background: var(--color-status-success-bg); color: var(--color-status-success-text);
  border-color: var(--color-status-success-border);
}
.dg-badge--warning {
  background: var(--color-status-warning-bg); color: var(--color-status-warning-text);
  border-color: var(--color-status-warning-border);
}
.dg-badge--error {
  background: var(--color-status-error-bg); color: var(--color-status-error-text);
  border-color: var(--color-status-error-border);
}
.dg-badge--brand {
  background: var(--color-surface-brand); color: var(--color-text-brand);
  border-color: var(--color-surface-brand);
}

/* ── Banners ───────────────────────────────────────────────────────────────── */
/*
 * The warning banner is load-bearing rather than decorative: a render warning means a
 * PDF that succeeded and is silently wrong, so it is PINNED, not a flash. See
 * documents/warnings.py, which already phrases each one as a consequence.
 */
.dg-banner {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 16px; border-radius: 10px;
  border: 1px solid transparent; font-size: 14px;
}
.dg-banner svg { flex: none; margin-top: 2px; }
.dg-banner-body { flex: 1; }
.dg-banner-body b { font-weight: 600; }
.dg-banner a, .dg-banner .dg-link-action { color: inherit; font-weight: 600; white-space: nowrap; }

.dg-banner--warning {
  background: var(--color-status-warning-bg); border-color: var(--color-status-warning-border);
  color: var(--color-status-warning-text);
}
.dg-banner--info {
  background: var(--color-status-info-bg); border-color: var(--color-status-info-border);
  color: var(--color-status-info-text);
}
.dg-banner--error {
  background: var(--color-status-error-bg); border-color: var(--color-status-error-border);
  color: var(--color-status-error-text);
}
.dg-banner--success {
  background: var(--color-status-success-bg); border-color: var(--color-status-success-border);
  color: var(--color-status-success-text);
}

/* A banner that describes the state of the ACCOUNT rather than the last action, so it sits in
   flow at the top of <main> and stays there. The margin is what stops it touching the screen's
   own sticky-feeling header, which supplies its own padding. Distinct from .dg-msgs
   deliberately: a fixed transient stack is the wrong home for something that is still true
   after a reload. */
.dg-banner--inflow {
  margin: calc(var(--spacing-5) * 1px) calc(var(--spacing-10) * 1px) 0;
}

/* Django messages ("Saved.", an engine failure) are feedback about the last action, not part
   of the page - and rendering them in flow at the top of <main> pushed the screen's own
   heading down every time one appeared. Signing in used to do it twice at once. Fixed to the
   bottom-right instead: nothing reflows, and it is clear of both the header's action buttons
   and the sidebar. No shadow, by the design's own rule that only two exist; the banner's
   border and solid background are what separate it from the page. */
.dg-msgs {
  position: fixed; right: 24px; bottom: 24px; z-index: 80;
  display: flex; flex-direction: column; gap: 8px;
  width: min(420px, calc(100vw - 48px));
}

/* Engine failures arrive as a typed code (engine/errors.py). The consequence goes in the
   banner body; the raw engine text goes behind this disclosure, never inline. */
.dg-disclosure { margin-top: 8px; font-size: 13px; }
.dg-disclosure summary { cursor: pointer; font-weight: 600; }
.dg-disclosure pre {
  margin: 8px 0 0; padding: 10px 12px; border-radius: 8px;
  background: var(--color-surface-default); border: 1px solid var(--color-border-muted);
  font-family: var(--font-mono); font-size: 12px; white-space: pre-wrap; overflow-x: auto;
}

/* ── Cards ─────────────────────────────────────────────────────────────────── */
/* Cards are FLAT - a 1px border, no shadow. Only two shadows exist in the whole
   design, and both are below (sign-in card, simulated paper). */

.dg-card {
  background: var(--color-surface-default);
  border: 1px solid var(--color-border-primary);
  border-radius: 12px;
}
.dg-card--pad { padding: 18px 20px; }
.dg-card-strip {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; background: var(--color-surface-muted);
  border-bottom: 1px solid var(--color-border-muted);
  border-radius: 12px 12px 0 0;
}
.dg-card-body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 14px; }

/* The 12px/600 uppercase label above a panel. */
.dg-eyebrow {
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
  color: var(--color-text-subtle);
}
.dg-card-title { font-family: var(--font-display); font-weight: 600; font-size: 17px;
  color: var(--color-text-heading); }
.dg-section-h2 { font-family: var(--font-display); font-weight: 600; font-size: 18px;
  color: var(--color-text-heading); }

/* Section rhythm on stacked screens: clearly more air BETWEEN sections than inside one,
 * so a heading binds to its own content instead of floating midway between two. A flat
 * 20px column (the first version of the Looks index) had no hierarchy at all - the
 * "Departments" heading sat as close to the Themes cards above it as to its own. */
/* Combined with .dg-content on the same element: this class is declared AFTER it, so the
 * 36px gap wins over .dg-content's 20px while the page padding comes through untouched.
 * Never give this class its own padding-top - a bare padding-top here would override the
 * whole of .dg-content's shorthand top, not add to it. */
.dg-sections { display: flex; flex-direction: column; gap: 36px; }
.dg-section { display: flex; flex-direction: column; gap: 16px; }
.dg-section-head { display: flex; flex-direction: column; gap: 4px; }
.dg-section-head .dg-section-h2, .dg-section-head .dg-meta { margin: 0; }

/* ── Tables ────────────────────────────────────────────────────────────────── */
/*
 * CSS grid rather than <table> markup would lose semantics for a screen reader, so
 * these are real tables with `display: grid` applied to the rows. Each screen sets its
 * own column template with --dg-cols, which is why there is no column sizing here.
 */
.dg-table { width: 100%; border-collapse: collapse; }
.dg-table thead tr, .dg-table tbody tr {
  display: grid; grid-template-columns: var(--dg-cols); gap: 16px; align-items: center;
}
.dg-table thead th {
  padding: 12px 0; text-align: left;
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
  color: var(--color-text-subtle);
}
.dg-table thead tr {
  padding: 0 20px; background: var(--color-surface-muted);
  border-radius: 12px 12px 0 0;
}
.dg-table tbody tr {
  padding: 16px 20px; border-bottom: 1px solid var(--color-border-muted);
}
.dg-table tbody tr:hover { background: var(--color-surface-muted); }
.dg-table tbody tr:last-child { border-bottom: 0; }
.dg-table td { padding: 0; }
.dg-cell-title { font-size: 15px; font-weight: 600; }
.dg-cell-sub { font-size: 13px; color: var(--color-text-subtle); }
.dg-cell-actions { display: flex; gap: 8px; justify-content: flex-end; }
.dg-fingerprint { font-family: var(--font-mono); font-size: 12px; color: var(--color-text-subtle); }

.dg-empty { padding: 32px 20px; text-align: center; color: var(--color-text-subtle); font-size: 14px; }

/* ── Inputs ────────────────────────────────────────────────────────────────── */

.dg-field { display: flex; flex-direction: column; gap: 6px; }
.dg-label { font-size: 13px; font-weight: 600; color: var(--color-text-secondary); }
.dg-help { font-size: 13px; color: var(--color-text-subtle); }

/* A small control with its explanation beside it, on one line where there is room.
 *
 * `align-items: center` rather than baseline: the button is 30px and the help text one line, so
 * baseline alignment leaves the glyphs sitting on the button's bottom edge. Wraps, because the
 * explanation is a sentence and a narrow column must not push the button off the card. */
.dg-inline-action {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing-3) * 1px);
  flex-wrap: wrap;
  margin-bottom: calc(var(--spacing-3) * 1px);
}
.dg-inline-action .dg-help { flex: 1 1 240px; min-width: 0; }

/* A row of fields where only SOME carry help text underneath.
 *
 * The naive `align-items: end` bottom-aligns the field boxes, so a field with a help line
 * is taller and its label and control ride 26px ABOVE its neighbours - which is what the
 * grant form on People & access looked like. Subgrid instead: the row owns three rows
 * (label, control, help) and each field opts into them, so labels align to labels and
 * controls to controls whether or not a field has help. A submit button in the row sits on
 * the control row.
 */
.dg-fieldrow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  grid-template-rows: auto auto auto;
  gap: 12px;
  align-items: start;
}
.dg-fieldrow > .dg-field {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  gap: 6px;
}
.dg-fieldrow > .lb-btn { grid-row: 2; }

.dg-input, .dg-select {
  height: 40px; padding: 0 12px;
  border: 1px solid var(--color-border-primary); border-radius: 8px;
  background: var(--color-surface-default); color: var(--color-text-primary);
  font-size: 15px; width: 100%; box-sizing: border-box;
}
textarea.dg-input { height: auto; min-height: 280px; padding: 12px; line-height: 1.6; }
.dg-input::placeholder { color: var(--color-text-subtle); }

/* An in-row control, for a table cell that carries its own form - the People screen sets a role
   per row. Matches .lb-btn--s so the select and the button beside it are the same height, and
   width:auto because a 100%-wide select inside a cell pushes the button onto its own line. */
.dg-select--s, .dg-input--xs {
  height: 32px; font-size: 13px; padding: 0 8px; width: auto; min-width: 110px;
}

.dg-search {
  position: relative; flex: 1; min-width: 240px;
  display: flex; align-items: center; gap: 8px;
  padding: 0 12px; height: 40px; border-radius: 8px;
  background: var(--color-surface-default); border: 1px solid var(--color-border-primary);
}
.dg-search svg { flex: none; color: var(--color-text-subtle); }
.dg-search input {
  flex: 1; border: 0; background: transparent; outline: none;
  color: var(--color-text-primary); font-size: 15px;
}
.dg-filters { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.dg-filters .dg-select { width: auto; min-width: 170px; }

/* Segmented control: the format switcher in the editor. */
.dg-segmented {
  display: inline-flex; gap: 2px; padding: 3px; border-radius: 8px;
  background: var(--color-surface-sunken);
}
.dg-segmented button, .dg-segmented a {
  padding: 5px 12px; border: 0; border-radius: 6px; background: transparent;
  color: var(--color-text-subtle); font-size: 13px; font-weight: 500; cursor: pointer;
}
.dg-segmented [aria-pressed="true"], .dg-segmented [aria-current="true"] {
  background: var(--color-surface-default); color: var(--color-text-primary); font-weight: 600;
}

/* Drop zone for pictures. 1.5px dashed, and it turns interactive-coloured on dragover. */
/* The drop zone is a <button>, and that is why it needs an explicit background.
 *
 * A button with no `background` takes the UA's `buttonface`, which is rgb(240,240,240) here
 * regardless of theme - nothing declares `color-scheme`, so Chrome's dark form controls never
 * apply. In dark mode that put subtle grey text (#ced4da) on near-white: a contrast ratio of
 * about 1.4:1, and the panel read as a white slab. Every other control in this file sets its
 * own background and none of them showed it.
 *
 * `font: inherit` for the same class of reason - a button does not inherit the page's font
 * size or weight, only the family that `body.dg button` sets.
 */
.dg-drop {
  border: 1.5px dashed var(--color-border-primary); border-radius: 10px;
  padding: 18px; text-align: center; width: 100%;
  background: var(--color-surface-muted);
  /* text-primary, not text-secondary: this is a button LABEL, and secondary resolves to
     #868e96 in the light scope, which is 3.15:1 on the muted surface - under AA for 14px
     text. Primary clears 13:1 in both scopes. */
  font: inherit; font-size: 14px; color: var(--color-text-primary); cursor: pointer;
}
.dg-drop:hover { border-color: var(--color-border-strong); background: var(--color-surface-sunken); }
.dg-drop.is-over {
  border-color: var(--color-interactive-active); color: var(--color-interactive-active);
}

/* An attached picture row, and its missing-reference variant. A missing picture is a
   warning rather than an error because the render SUCCEEDS - asciidoctor only warns -
   and leaves an empty space in the PDF. */
.dg-asset {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: 8px; background: var(--color-surface-muted);
}
.dg-asset--missing {
  background: var(--color-status-warning-bg);
  border: 1px solid var(--color-status-warning-border);
  color: var(--color-status-warning-text);
}
.dg-asset-thumb {
  width: 34px; height: 34px; flex: none; border-radius: 6px;
  background: var(--color-surface-secondary); object-fit: cover;
}
.dg-asset-text { flex: 1; min-width: 0; }
.dg-asset-name { font-size: 14px; font-weight: 500; }
.dg-asset-meta { font-size: 12px; color: var(--color-text-subtle); }

/* ── Grids used by more than one screen ────────────────────────────────────── */

.dg-two-col {
  display: grid; grid-template-columns: minmax(420px, 1fr) minmax(420px, 1fr);
  gap: 24px; align-items: start;
}
.dg-main-rail { display: grid; grid-template-columns: 1fr 340px; gap: 24px; align-items: start; }
.dg-sticky { position: sticky; top: 24px; }
.dg-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
/* 220px minimum, not 180: a two-word type name plus its own line for a badge need the
 * room, and at 180 the caption was the cramped corner of every look detail page. */
.dg-cover-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
.dg-kv { display: flex; justify-content: space-between; gap: 16px; font-size: 14px; }
.dg-kv dt { color: var(--color-text-subtle); }
.dg-kv dd { margin: 0; text-align: right; font-weight: 500; }

/* Below ~1100px both two-column layouts stack and the sidebar becomes a top bar.
   Not designed in detail - desktop is the real use case - so this is damage control,
   not a designed breakpoint. */
@media (max-width: 1100px) {
  .dg-shell { flex-direction: column; }
  .dg-sidebar {
    width: auto; border-right: 0; border-bottom: 1px solid var(--color-border-primary);
  }
  .dg-nav { flex-direction: row; flex-wrap: wrap; }
  .dg-spacer { display: none; }
  .dg-two-col, .dg-main-rail { grid-template-columns: minmax(0, 1fr); }
  .dg-sticky { position: static; }
  .dg-header, .dg-content { padding-left: 20px; padding-right: 20px; }
}

/* ── Look cards ────────────────────────────────────────────────────────────── */

.dg-look { overflow: hidden; display: block; color: inherit; }
.dg-look:hover { border-color: var(--color-border-strong); color: inherit; }
.dg-look-band { height: 76px; background: var(--gradient-peacock); }
/* 10px gap and title-takes-the-slack are the prototype's own values. space-between here
 * was wrong with two badges: it spread title, "Default" and "Built in" evenly across the
 * card, leaving a badge floating mid-air. flex:1 on the title clusters badges right. */
.dg-look-body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 10px; }
.dg-look-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dg-look-head .dg-card-title { flex: 1; }
.dg-swatches { display: flex; gap: 8px; }
.dg-swatch { width: 24px; height: 24px; border-radius: 6px; border: 1px solid var(--color-border-muted); }

/* ── Sign in ───────────────────────────────────────────────────────────────── */

.dg-signin { flex: 1; display: grid; place-items: center; padding: 48px 24px; }
.dg-signin-card {
  width: 100%; max-width: 400px; overflow: hidden;
  background: var(--color-surface-default);
  border: 1px solid var(--color-border-primary); border-radius: 12px;
  /* One of only two shadows in the design. rgba() on a fixed midnight, not a token,
     because Peacock ships no shadow tokens and the handoff gives these values. */
  box-shadow: 0 1px 2px rgba(27, 5, 46, .06), 0 8px 32px rgba(27, 5, 46, .06);
}
.dg-signin-edge { height: 4px; background: var(--gradient-peacock); }
.dg-signin-body { padding: 36px 32px 32px; display: flex; flex-direction: column; gap: 24px; }
.dg-signin-body h1 { font-size: 24px; font-weight: 600; }
.dg-signin-foot {
  margin: 0; padding-top: 20px; border-top: 1px solid var(--color-border-muted);
  font-size: 13px; color: var(--color-text-subtle);
}

/* ── Simulated paper: THE DOCUMENTED COLOUR EXCEPTION ──────────────────────── */
/*
 * Everything below uses literal hex, and that is correct. These elements depict a
 * PRINTED PAGE. Paper does not follow the UI theme: in dark mode a document preview
 * must still be white with dark text, because that is what comes out of the printer.
 *
 * The five literals are named in the handoff for exactly this reason:
 *   #ffffff page, #54009c title, #eee6f5 rule, #495057 subtitle, #868e96 meta.
 *
 * Do not "fix" these to tokens. Everything OUTSIDE the page - the stage it sits on,
 * the card around it - is tokenised, as it should be.
 */
.dg-stage {
  padding: 20px; background: var(--color-surface-sunken);
  display: grid; place-items: center; border-radius: 0 0 12px 12px;
}
.dg-paper {
  width: 100%; max-width: 420px; aspect-ratio: 1 / 1.414;
  background: #ffffff; border: 1px solid var(--color-border-primary);
  border-radius: 4px; overflow: hidden;
  box-shadow: 0 8px 24px rgba(27, 5, 46, .10);
  display: flex; flex-direction: column;
}
.dg-paper--lg { max-width: 520px; box-shadow: 0 12px 32px rgba(27, 5, 46, .12); }
.dg-paper-edge { height: 8px; background: var(--gradient-peacock); flex: none; }
.dg-paper--lg .dg-paper-edge { height: 10px; }
.dg-paper-body { padding: 36px 34px; display: flex; flex-direction: column; flex: 1; }
.dg-paper--lg .dg-paper-body { padding: 44px 42px; }
.dg-paper-logo { height: 22px; }
.dg-paper--lg .dg-paper-logo { height: 26px; }
.dg-paper-title {
  font-family: var(--font-display); font-weight: 600; font-size: 26px; color: #54009c;
}
.dg-paper--lg .dg-paper-title { font-size: 34px; }
.dg-paper-sub { font-size: 15px; color: #495057; }
.dg-paper--lg .dg-paper-sub { font-size: 18px; }
.dg-paper-rule { height: 2px; background: #eee6f5; margin: 14px 0; }
.dg-paper-meta { font-size: 12px; color: #868e96; }
.dg-paper--lg .dg-paper-meta { font-size: 13px; }

/* "No preview yet" - what the editor's preview panel shows before a render exists.
 *
 * It replaced a simulated page, and the reason is worth keeping: that simulation drew a white
 * sheet with a gradient edge and a purple title, which is precisely the `paper` look. Once
 * `paper` existed as a real look, an `lb` document was being shown an accurate preview of the
 * WRONG one. A prompt cannot be wrong about what the PDF will look like. */
.dg-preview-none {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 48px 32px; text-align: center; color: var(--color-text-subtle);
  max-width: 420px;
}
.dg-preview-none .dg-copy { color: var(--color-text-primary); margin: 0; }
.dg-preview-none .dg-help { margin: 0; }

/* The page strip under the editor's preview panel.
 *
 * Numbered placeholders, one per page of the LAST render, drawn only when a real count exists -
 * see the template comment. The sheets use the documented #ffffff paper literal for the same
 * reason .dg-paper does: they depict printed paper, which does not follow the UI theme. Their
 * frame, the label and the overflow chip are tokenised.
 *
 * The list scrolls inside itself. A long document must not make the whole page scroll sideways,
 * which is the rule every wide element here follows. */
.dg-pagestrip-wrap { padding: 12px 16px 16px; display: flex; flex-direction: column; gap: 8px; }
.dg-pagestrip-label {
  margin: 0; font-size: 12px; color: var(--color-text-subtle);
}
.dg-pagestrip {
  list-style: none; margin: 0; padding: 0 0 4px;
  display: flex; gap: 8px; overflow-x: auto;
}
.dg-pagestrip-page {
  flex: none; width: 34px; aspect-ratio: 1 / 1.414;
  background: #ffffff; border: 1px solid var(--color-border-primary); border-radius: 3px;
  display: grid; place-items: center;
  font-size: 11px; color: #868e96;
}
.dg-pagestrip-more {
  flex: none; align-self: center; padding: 0 8px;
  font-size: 12px; color: var(--color-text-subtle);
}

/* "Making the PDF" - visible between pressing Render preview and the frame's load event.
 * Absolute over the whole stage so a re-render also covers the stale preview, which no
 * longer describes what is coming. The [hidden] guard matters: display:flex on the class
 * would otherwise beat the attribute - the exact specificity trap from docs/ui-iteration.md. */
.dg-stage { position: relative; }
.dg-preview-loading {
  position: absolute; inset: 0; border-radius: 0 0 12px 12px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 48px 32px; text-align: center;
  background: var(--color-surface-sunken); color: var(--color-text-subtle);
}
.dg-preview-loading[hidden] { display: none; }
.dg-preview-loading .dg-copy { color: var(--color-text-primary); margin: 0; }
.dg-preview-loading .dg-help { margin: 0; max-width: 420px; }
.dg-spinner { animation: dg-spin 1s linear infinite; }
@keyframes dg-spin { to { transform: rotate(360deg); } }
/* The words carry the message; the motion is optional. */
@media (prefers-reduced-motion: reduce) { .dg-spinner { animation: none; } }

/* Embedded real PDF. The shadow and gradient edge stay on the container so a slow or
   empty frame still looks deliberate rather than broken. */
.dg-pdf-frame { width: 100%; aspect-ratio: 1 / 1.414; border: 0; display: block; background: #ffffff; }

/* Page thumbnails under a preview. */
.dg-thumbs { display: flex; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--color-border-muted); }
.dg-thumb {
  width: 38px; height: 54px; border-radius: 3px;
  background: var(--color-surface-sunken); border: 1px solid var(--color-border-primary);
}
.dg-thumb.is-current { background: var(--gradient-kepler-51); border-color: transparent; }

/* A cover thumbnail on the look-detail screen. Same printed-paper reasoning. */
.dg-cover {
  aspect-ratio: 1 / 1.414; background: #ffffff;
  border: 1px solid var(--color-border-primary); border-radius: 8px 8px 0 0;
  overflow: hidden; display: flex; flex-direction: column;
}
.dg-cover-edge { height: 6px; background: var(--gradient-peacock); flex: none; }
.dg-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dg-cover-missing {
  flex: 1; display: grid; place-items: center;
  font-size: 12px; color: var(--color-text-subtle); text-align: center; padding: 8px;
}
.dg-cover-caption {
  padding: 12px 14px; border: 1px solid var(--color-border-primary); border-top: 0;
  border-radius: 0 0 8px 8px; background: var(--color-surface-default);
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
}

/* ── Screen 3: the editor's writing surface ────────────────────────────────────
 *
 * Everything else this screen needs already existed - .dg-two-col, .dg-segmented, .dg-drop,
 * .dg-asset*, .dg-paper* and .dg-thumb were all written when the stylesheet was built for the
 * nine screens. Only the toolbar and the surface itself were missing, because the editor
 * template was never written: the screen was left as Wagtail's stock form.
 */

.dg-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.dg-copy { font-size: 14px; color: var(--color-text-secondary); }

/* Toolbar row: 30x30 icon buttons, a 1px divider, then text controls at 13px/500. */
.dg-toolbar {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 12px; border-bottom: 1px solid var(--color-border-muted);
}
.dg-tool {
  height: 30px; padding: 0 10px; border: 0; border-radius: 6px;
  background: transparent; color: var(--color-text-secondary);
  font-size: 13px; font-weight: 500; cursor: pointer;
}
.dg-tool--icon { width: 30px; padding: 0; font-size: 14px; }
.dg-tool:hover { background: var(--color-surface-muted); color: var(--color-text-primary); }
.dg-tool-divider { width: 1px; height: 18px; background: var(--color-border-muted); margin: 0 4px; }

/* The toolbar now carries every feature the engine accepts, so it has to wrap on a narrow
   column rather than push the panel wider than the page. */
.dg-toolbar { flex-wrap: wrap; row-gap: 4px; }

/* The heading-level select, sized to sit in the row rather than dominate it. */
.dg-tool-select {
  height: 30px; padding: 0 8px; border-radius: 6px;
  border: 1px solid var(--color-border-primary);
  background: var(--color-surface-default); color: var(--color-text-primary);
  font-size: 13px; font-weight: 500;
}

/* The link field, revealed by the Link button. Inline, because a modal dialog blocks the page
   and the design has no dialog component. */
.dg-tool-url { display: inline-flex; align-items: center; gap: 4px; }
.dg-input--s { height: 30px; font-size: 13px; width: 220px; }

/* What the format control's conversion did, or why it did nothing. */
.dg-format-notice { margin: 0; padding: 8px 12px 0; }

/* The writing surface. `text-wrap: pretty` is the handoff's instruction and it is what stops a
 * heading breaking with one word on the second line. */
.dg-surface {
  padding: 20px 22px; min-height: 280px; outline: none;
  display: flex; flex-direction: column; gap: 14px;
  font-size: 15px; line-height: 1.65; color: var(--color-text-primary);
  text-wrap: pretty;
}
.dg-surface h2, .dg-surface h3 {
  font-family: var(--font-display); font-weight: 600; font-size: 19px;
  color: var(--color-text-heading); margin: 0;
}
.dg-surface p, .dg-surface ul, .dg-surface ol { margin: 0; }
.dg-surface ul, .dg-surface ol { padding-left: 22px; }
/* Raw source is code, so it gets the mono face and no gap-based block spacing. */
.dg-surface--code {
  display: block; width: 100%; box-sizing: border-box; resize: vertical;
  border: 0; background: transparent;
  font-family: var(--font-mono); font-size: 13.5px; line-height: 1.6;
}
.dg-surface--code:focus { outline: none; }

/* ── The document type form, as a front-end page ─────────────────────────────
 *
 * Moved here from wagtail.css when the themes screens left Wagtail's chrome (Solo 310):
 * these rules must load wherever the form renders, and docgen.css is the sheet the dg
 * shell and the admin both carry. The .fields reset exists because the dg pages have no
 * Wagtail stylesheet to flatten a bare <ul>.
 */
.dg-type-form .fields {
  list-style: none;
  margin: 0;
  padding: 0;
}
.dg-type-form input[type="text"], .dg-type-form input[type="number"],
.dg-type-form select, .dg-type-form textarea {
  border-radius: 8px;
  border: 1px solid var(--color-border-primary);
  background: var(--color-surface-default);
  color: var(--color-text-primary);
  min-height: 40px;
  padding: 0 12px;
  width: 100%;
  max-width: 560px;
  font-family: var(--font-sans);
  font-size: 14px;
}
.dg-type-form .help-block {
  font-size: 13px;
  color: var(--color-text-secondary);
  margin: 6px 0 0;
}
.dg-type-form .fields > li {
  padding: 0 0 20px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--color-border-muted);
}
.dg-type-form .fields > li:last-child {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: 0;
}
.dg-type-form .fields > li > label {
  display: block;
  margin-bottom: 6px;
  font-weight: 600;
}
.dg-type-form .fields > li > .help-block { margin-top: 6px; }
.dg-type-form .fields > li > input[type="file"] { margin-top: 10px; }
.dg-type-form .fields > li.dg-check-row > label {
  display: inline;
  margin-bottom: 0;
}
.dg-type-form h2 {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--color-border-muted);
}
.dg-type-attrs .dg-check-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 10px;
  align-items: center;
}
.dg-type-attrs .dg-check-row > input[type="checkbox"] { margin: 0; }
.dg-type-attrs .dg-check-row > label { margin: 0; }
.dg-type-attrs .dg-check-row > .help-block { grid-column: 2; margin: 0; }
.dg-type-attrs code {
  font-family: var(--font-mono); font-size: 12px;
  color: var(--color-text-subtle); font-weight: 400;
}
.dg-type-form .dg-form-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px solid var(--color-border-muted);
}
.dg-type-form .dg-generate-row {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
}
.dg-type-form .dg-generate-row select { max-width: 320px; }
.dg-type-form .dg-generate-row input[type="text"] { max-width: 320px; }
.dg-type-form .dg-generate-check {
  display: flex; align-items: center; gap: 8px;
  margin-top: 10px; font-weight: 600;
}
.dg-type-form .dg-generate-check input { margin: 0; }
.dg-type-form .dg-generate-preview {
  display: block; margin-top: 12px; width: 260px; height: auto;
  border: 1px solid var(--color-border-primary); border-radius: 6px;
  background: var(--color-surface-sunken);
}
