/* =====================================================================
   TACTILE — the physical layer.

   One law, applied to every control in the product: a thing you can
   press rests on a visible lip, and pressing it takes the lip away and
   moves the light from under it to above it. 40ms down (below the
   threshold where a delay is felt), 110ms back up with a slight
   overshoot so the return is seen.

   WHY THIS EXISTS
   ---------------
   The tool is opened every working morning by people who are not in a
   building together. A page that answers a click by silently changing
   colour feels like paperwork; a control that moves under the finger
   feels like an instrument. The difference is roughly forty lines of
   CSS and no runtime cost at all — no JavaScript, no images, no extra
   requests.

   HOW IT IS APPLIED
   -----------------
   This sheet loads LAST on every signed-in page, so it wins on
   specificity ties without any of the component sheets needing to know
   it exists. It deliberately targets ELEMENTS and the handful of button
   classes this app actually uses, rather than adding a class to a
   hundred call sites — that is what made the old per-page drift
   possible in the first place.

   THREE MATERIALS, NO MORE
   ------------------------
   • Paper   — anything a person wrote. Flat, warm, never glows.
   • Key     — anything you can press. It has a lip. No lip means it
               does nothing when you touch it, and that is a promise.
   • Machine — graphite with a lit edge: cron, health, and every line a
               model wrote. See "machine" at the bottom.

   Dark mode is a first-class citizen here, not an afterthought: every
   value below is a token, and the dark block redefines the tokens
   rather than re-stating the rules.
   ===================================================================== */

:root {
  /* The material tokens live in styles.css with the rest of the design
     system now; what stays here is only what describes the PRESS. */
  --key-face-1:  #ffffff;
  --key-face-2:  var(--surface-3);
  --key-lip:     var(--line-3);
  --key-line:    var(--line-3);
  --key-ink:     var(--ink);
  --key-hi:      rgba(255, 255, 255, 1);
  --key-cast:    rgba(38, 32, 24, .5);
  --key-in:      rgba(38, 32, 24, .16);

  --key-acc-1:   #e0592f;
  --key-acc-2:   #c2410c;
  --key-acc-lip: #93300a;
  --key-acc-ink: #ffffff;

  --key-solid-lip: color-mix(in srgb, var(--ink) 45%, #000);
  --key-cta-lip:   color-mix(in srgb, var(--accent) 55%, #000);

  --well-bg:     var(--surface);
  --well-in:     rgba(38, 32, 24, .13);

  --mach-1:      var(--mach);
  --mach-2:      var(--mach-2);

  --press-travel: 3px;
  --press-down:   40ms;
  --press-up:     110ms;
  --press-ease:   cubic-bezier(.2, .9, .3, 1.2);
}

[data-theme="dark"] {
  /* A key in the dark is lit from above like everything else: the face
     lightens towards the top and the lip is darker than the page. */
  --key-face-1:  #2a2c31;
  --key-face-2:  #212327;
  --key-lip:     #06070a;
  --key-line:    #34373d;
  --key-hi:      rgba(255, 255, 255, .07);
  --key-cast:    rgba(0, 0, 0, .85);
  --key-in:      rgba(0, 0, 0, .6);

  --key-acc-1:   #e07a52;
  --key-acc-2:   #c2552a;
  --key-acc-lip: #55220c;
  --key-acc-ink: #14100d;

  --key-solid-lip: #06070a;
  --key-cta-lip:   #55220c;

  --well-bg:     #0d0e12;
  --well-in:     rgba(0, 0, 0, .65);
}

/* =====================================================================
   0. THE DESK

   The app sits on paper with a woven tooth rather than on a flat fill.
   It is two repeating gradients and costs nothing, and it is the single
   cheapest thing that stops a page reading as a browser window.
   ===================================================================== */
body {
  background-color: var(--ground);
  background-image:
    radial-gradient(circle at 20% 12%, rgba(255, 255, 255, .5), transparent 45%),
    repeating-linear-gradient(0deg,  rgba(120, 110, 95, .035) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(120, 110, 95, .035) 0 1px, transparent 1px 3px);
  background-attachment: fixed;
}
[data-theme="dark"] body {
  background-color: var(--ground);
  background-image:
    radial-gradient(circle at 20% 10%, rgba(255, 255, 255, .045), transparent 42%),
    repeating-linear-gradient(0deg,  rgba(255, 255, 255, .018) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, .018) 0 1px, transparent 1px 3px);
}

/* =====================================================================
   1. THE PRESS — every button, everywhere
   ===================================================================== */

button,
.btn,
.ghost-btn,
.auth-primary,
.icon-btn,
.admin-btn,
.set-btn,
.pill-btn,
a.btn,
input[type="submit"],
input[type="button"] {
  -webkit-tap-highlight-color: transparent;
  transition:
    transform var(--press-up) var(--press-ease),
    box-shadow var(--press-up) ease-out,
    background-color 120ms ease-out,
    border-color 120ms ease-out,
    color 120ms ease-out;
}

button:active,
.btn:active,
.ghost-btn:active,
.auth-primary:active,
.icon-btn:active,
.admin-btn:active,
.set-btn:active,
.pill-btn:active,
a.btn:active,
input[type="submit"]:active,
input[type="button"]:active {
  transform: translateY(2px);
  transition-duration: var(--press-down);
}

/* A disabled control must not pretend to move. */
button:disabled,
button[aria-disabled="true"],
.btn:disabled,
input[type="submit"]:disabled {
  transform: none !important;
  box-shadow: none !important;
  cursor: not-allowed;
}

/* Keyboard users get the same affordance as the mouse, and a ring that
   survives both themes. */
button:focus-visible,
.btn:focus-visible,
.ghost-btn:focus-visible,
.auth-primary:focus-visible,
.icon-btn:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* =====================================================================
   2. KEYS — the buttons that carry a real lip

   Applied to the app's actual button classes rather than to `button`,
   because plenty of buttons in here are bare icons inside a toolbar and
   a lip on those would be noise.
   ===================================================================== */

.btn,
.ghost-btn,
.set-btn,
.admin-btn,
a.btn {
  border: 1px solid var(--key-line);
  background: linear-gradient(var(--key-face-1), var(--key-face-2));
  color: var(--key-ink);
  box-shadow:
    0 3px 0 var(--key-lip),
    0 7px 12px -8px var(--key-cast),
    inset 0 1px 0 var(--key-hi);
}

.btn:hover,
.ghost-btn:hover,
.set-btn:hover,
.admin-btn:hover {
  background: linear-gradient(var(--key-face-1), var(--key-face-1));
}

.btn:active,
.ghost-btn:active,
.set-btn:active,
.admin-btn:active,
a.btn:active {
  transform: translateY(var(--press-travel));
  box-shadow:
    0 0 0 var(--key-lip),
    inset 0 2px 4px var(--key-in);
}

/* The accent key: at most one per screen — the thing you came to do. */
.btn--primary,
.btn.primary,
.auth-primary,
.btn-accent {
  border: 1px solid var(--key-acc-lip);
  background: linear-gradient(var(--key-acc-1), var(--key-acc-2));
  color: var(--key-acc-ink);
  box-shadow:
    0 3px 0 var(--key-acc-lip),
    0 7px 12px -8px var(--key-cast),
    inset 0 1px 0 rgba(255, 255, 255, .3);
}
.btn--primary:active,
.btn.primary:active,
.auth-primary:active,
.btn-accent:active {
  transform: translateY(var(--press-travel));
  box-shadow: 0 0 0 var(--key-acc-lip), inset 0 2px 5px rgba(70, 25, 5, .45);
}

/* A key that is already down and stays down: the selected tab, the
   filter that is on. It reads as "engaged", the way a lift button does,
   without needing a colour to say so. */
.is-held,
[aria-pressed="true"],
[aria-selected="true"].tab,
.tab.is-active,
.seg.is-on {
  transform: translateY(var(--press-travel));
  background: var(--surface-2);
  box-shadow: 0 0 0 var(--key-lip), inset 0 2px 4px var(--key-in);
}

/* ---------------------------------------------------------------------
   2b. THE REST OF THIS APP'S BUTTONS

   Written out by name rather than by element, because plenty of
   `button`s here are bare icons in a toolbar or a drag handle in a row,
   and a lip on those is noise. This list is every button class the
   stylesheets actually define.
   --------------------------------------------------------------------- */

/* Raised, neutral: the ordinary secondary action. */
.td-btn--ghost,
.ob-btn--ghost,
.ob-cta--quiet,
.cta-secondary,
.email-btn,
.mtg-daybtn,
.google-btn,
.fb-tabbtn,
.rem-tab,
.lb-tab {
  box-shadow:
    0 3px 0 var(--key-lip),
    0 7px 12px -8px var(--key-cast),
    inset 0 1px 0 var(--key-hi);
  transition:
    transform var(--press-up) var(--press-ease),
    box-shadow var(--press-up) ease-out,
    background-color 120ms ease-out;
}
.td-btn--ghost:active,
.ob-btn--ghost:active,
.ob-cta--quiet:active,
.cta-secondary:active,
.email-btn:active,
.mtg-daybtn:active,
.google-btn:active,
.fb-tabbtn:active,
.rem-tab:active,
.lb-tab:active {
  transform: translateY(var(--press-travel));
  box-shadow: 0 0 0 var(--key-lip), inset 0 2px 4px var(--key-in);
  transition-duration: var(--press-down);
}

/* The primary action — Save, Create, Make a link, Add.
   It was painted `background: var(--ink)`, which is near-BLACK in light
   mode and near-WHITE in dark: in dark mode every primary button on
   every page was a bright white slab, the single loudest thing on the
   screen and the opposite of what it should be.

   It is the accent key in both themes now — one loud control per
   screen, the same terracotta the design uses, with a real lip. */
.td-btn,
.td-btn--ok,
.td-btn--warn {
  border: 1px solid var(--key-acc-lip);
  background: linear-gradient(var(--key-acc-1), var(--key-acc-2));
  color: var(--key-acc-ink);
  box-shadow:
    0 3px 0 var(--key-acc-lip),
    0 7px 12px -8px var(--key-cast),
    inset 0 1px 0 rgba(255, 255, 255, .3);
}
.td-btn:hover:not(:disabled),
.td-btn--ok:hover:not(:disabled) {
  background: linear-gradient(var(--key-acc-1), var(--key-acc-1));
}
.td-btn:active,
.td-btn--ok:active,
.td-btn--warn:active {
  transform: translateY(var(--press-travel));
  box-shadow: 0 0 0 var(--key-acc-lip), inset 0 2px 5px rgba(70, 25, 5, .45);
  transition-duration: var(--press-down);
}
/* Same fault, two more places: a button painted with the ink colour is
   a black slab in light mode and a WHITE one in dark. */
.fb-submit {
  border: 1px solid var(--key-acc-lip);
  background: linear-gradient(var(--key-acc-1), var(--key-acc-2));
  color: var(--key-acc-ink);
  box-shadow: 0 3px 0 var(--key-acc-lip), inset 0 1px 0 rgba(255, 255, 255, .3);
}
.fb-submit:active {
  transform: translateY(var(--press-travel));
  box-shadow: 0 0 0 var(--key-acc-lip), inset 0 2px 5px rgba(70, 25, 5, .45);
}
.admin-pager-link.is-active {
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--ink);
  box-shadow: inset 0 2px 4px var(--key-in);
}

/* The quiet sibling stays a plain key. */
.td-btn--ghost {
  border: 1px solid var(--key-line);
  background: linear-gradient(var(--key-face-1), var(--key-face-2));
  color: var(--key-ink);
}

/* Accent calls to action. */
.rev-cta,
.ob-cta,
.ob-btn--primary,
.cta-primary,
.wn-cta,
.header-cta,
.midcta {
  box-shadow: 0 3px 0 var(--key-cta-lip), 0 8px 14px -9px var(--key-cast);
}
.rev-cta:active,
.ob-cta:active,
.ob-btn--primary:active,
.cta-primary:active,
.wn-cta:active,
.header-cta:active,
.midcta:active {
  transform: translateY(var(--press-travel));
  box-shadow: 0 0 0 var(--key-cta-lip), inset 0 2px 5px rgba(0, 0, 0, .35);
  transition-duration: var(--press-down);
}

/* A selected tab is a key that never came back up — the same signal a
   lift button gives you, with no underline and no colour change. */
.fb-tabbtn.is-on,
.fb-tabbtn[aria-selected="true"],
.rem-tab.is-on,
.rem-tab[aria-selected="true"],
.lb-tab.is-on,
.lb-tab[aria-selected="true"] {
  transform: translateY(var(--press-travel));
  box-shadow: 0 0 0 var(--key-lip), inset 0 2px 4px var(--key-in);
}

/* Icon buttons stay flat until touched: a lip on a 32px toolbar icon
   reads as clutter, but the press still has to be felt. */
.icon-btn:active,
.avatar-btn:active { transform: translateY(2px); }

/* =====================================================================
   3. WELLS — anything you type into is a slot cut into the surface
   ===================================================================== */

/* Wrapped in :where() so this whole block carries ZERO specificity.

   The tactile layer loads last, which is what lets it win ties — and
   that is wrong for inputs. Plenty of fields in this product are
   deliberately borderless: the add row across the foot of the board,
   the cells of the import review sheet, the header search. Painting a
   well over those produced exactly the mismatched box in the
   screenshot: a rounded outline around an input that was supposed to
   be part of its surface.

   With :where(), any component rule beats this by default and the well
   is only what an unstyled input falls back to. */
:where(
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="search"],
  input[type="url"],
  input[type="number"],
  input[type="date"],
  input[type="time"],
  input[type="datetime-local"],
  select,
  textarea
) {
  background: var(--well-bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: inset 0 2px 4px var(--well-in);
  color: var(--ink);
  transition: box-shadow 120ms ease-out, border-color 120ms ease-out;
}

/* The named field classes DO want the well, and say so at their own
   specificity rather than relying on the element fallback. */
.auth-input,
.field-input,
.imp-input {
  background: var(--well-bg);
  border: 1px solid var(--line);
  box-shadow: inset 0 2px 4px var(--well-in);
  color: var(--ink);
  transition: box-shadow 120ms ease-out, border-color 120ms ease-out;
}

:where(input, select, textarea):focus,
.auth-input:focus,
.field-input:focus,
.imp-input:focus {
  border-color: var(--accent);
  box-shadow: inset 0 2px 4px var(--well-in), 0 0 0 3px var(--accent-soft);
  outline: none;
}

/* =====================================================================
   4. PAPER — cards, panels, tiles

   Paper sits ON the page and casts a small shadow. When its work is
   finished it stops floating and settles into a dent instead, which is
   the single most useful state signal in the product: you can see at a
   glance which rows are still live.
   ===================================================================== */

.panel,
.admin-card,
.set-card,
.tile,
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}

/* A finished row is pressed into the page. */
.task[data-status="1"],
.task.is-done,
tr.is-done { background: var(--surface-2); }
/* The edge that says "done" is set in 4b, with the rest of the state
   edges, so this rule must not also write box-shadow. */

/* ---------------------------------------------------------------------
   4b. THE STATE EDGE

   The rule the design canvas is built on: ONE line of colour per row,
   down the left edge, and nothing else on the card is coloured. A
   column of tasks then reads as a single vertical line — grey resting,
   orange due, red blocked, blue in review, green done — instead of the
   seven-chips-of-different-colours the board carries today.

   Everything below reads state the markup already carries: `data-stage`
   and `data-status` on the row, and the chip classes inside it. The
   :has() selectors are the only part a very old browser will miss, and
   what it misses is a grey edge rather than a broken layout.
   --------------------------------------------------------------------- */

/* Drawn as an inset shadow rather than a pseudo-element: the board's
   cards are rounded, and a 3px bar positioned at left:0 pokes out of
   the corners. An inset shadow follows the border radius exactly and
   costs no extra box. */
.task {
  position: relative;
  box-shadow: inset 3px 0 0 var(--st-rest);
}
.board-col .task {
  box-shadow: inset 3px 0 0 var(--st-rest), 0 1px 2px rgba(0, 0, 0, .05);
}

/* Priority order: what is urgent, then what is stuck, then what is
   waiting on somebody else, then what is finished. The last rule that
   matches wins, which is why done is at the bottom. */
.task:has(.due-chip--today),
.task:has(.pri-chip--p1)        { box-shadow: inset 3px 0 0 var(--st-due); }
.task:has(.due-chip--overdue),
.task:has(.pri-chip--p0)        { box-shadow: inset 3px 0 0 var(--st-blocked); }
.task[data-stage="blocked"]     { box-shadow: inset 3px 0 0 var(--st-blocked); }
.task[data-stage="in_review"]   { box-shadow: inset 3px 0 0 var(--st-review); }
.task[data-status="1"]          { box-shadow: inset 3px 0 0 var(--st-done); }

.board-col .task:has(.due-chip--today),
.board-col .task:has(.pri-chip--p1)      { box-shadow: inset 3px 0 0 var(--st-due), 0 1px 2px rgba(0,0,0,.05); }
.board-col .task:has(.due-chip--overdue),
.board-col .task:has(.pri-chip--p0)      { box-shadow: inset 3px 0 0 var(--st-blocked), 0 1px 2px rgba(0,0,0,.05); }
.board-col .task[data-stage="blocked"]   { box-shadow: inset 3px 0 0 var(--st-blocked), 0 1px 2px rgba(0,0,0,.05); }
.board-col .task[data-stage="in_review"] { box-shadow: inset 3px 0 0 var(--st-review), 0 1px 2px rgba(0,0,0,.05); }
/* Finished work stops floating and settles into the page. */
.board-col .task[data-status="1"]        { box-shadow: inset 3px 0 0 var(--st-done), inset 0 1px 2px rgba(38,32,24,.08); }

/* With the edge carrying the state, the chips go quiet. They still say
   what they say — they just stop competing with each other, which is
   the whole point of moving the colour to one place. */
.task .pri-chip,
.task .due-chip,
.task .sub-chip {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-3);
  font-weight: 600;
}
/* Two exceptions, because they are facts rather than labels: something
   already overdue, and something a person is blocked on. */
.task .due-chip--overdue { border-color: var(--st-blocked); color: var(--st-blocked); }

/* The board's columns are paper on a desk, not panes in a window. */
.board-col {
  box-shadow:
    0 2px 4px -2px rgba(38, 32, 24, .10),
    0 12px 24px -20px rgba(38, 32, 24, .45);
}
[data-theme="dark"] .board-col {
  box-shadow:
    0 2px 4px -2px rgba(0, 0, 0, .6),
    0 14px 28px -22px rgba(0, 0, 0, .9);
}

/* =====================================================================
   4c. PAPER, EVERYWHERE ELSE

   The board is not the only page. Every other surface in the product —
   settings, review, projects, meetings, teams, insights, the admin
   panel — is built from the same three materials, so that moving
   between them feels like moving around one object rather than between
   pages of a website.
   ===================================================================== */

/* The header is a strip of paper laid over the desk, not a browser
   chrome bar: it casts a shadow rather than drawing a border. */
.app-header {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 var(--line-2), 0 10px 20px -22px rgba(38, 32, 24, .5);
}

/* Section headings are the display face. This is the single most
   visible piece of the design system and it was applied on about half
   the pages. */
h1, h2,
.panel-title h2,
.set-card h2,
.rev-title,
.in-h2,
.pl-title,
.mtg-title {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--ink);
}

/* Anything that labels rather than speaks is mono, small, spaced and
   quiet — the tag on a file rather than a sentence. */
.panel-tag,
.set-label,
.rev-label,
.col-name,
.tile-label,
.chip-label,
.kbd-hint {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* .admin-fine is PROSE — the sentence under a heading that explains
   what a screen is for. It briefly got the label treatment above and
   turned three paragraphs of the AI-key page into 10px uppercase mono.
   Stated explicitly here so it cannot be swept up again. */
.admin-fine,
.set-hint,
.rev-fine {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.6;
  letter-spacing: normal;
  text-transform: none;
  color: var(--ink-3);
}

/* A page's opening sentence is not a hint — it says what the screen is
   for, and it was sitting at the same grey as disabled text. */
.rev-sub,
.set-sub,
.in-sub,
.imp-sub {
  color: var(--ink-2);
}

/* Panels sit ON the ground. Their heads get a hairline, not a fill —
   a shaded header band makes every panel look like a table. */
.panel {
  border-radius: var(--radius);
  overflow: hidden;
}
.panel-head {
  background: var(--surface);
  border-bottom: 1px solid var(--line-2);
}

/* Lists of work read like the board: one line of colour, quiet rows. */
.rev-item,
.pl-card,
.mtg-item,
.pi-item,
.tm-row {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: 0 1px 2px rgba(38, 32, 24, .05);
}

/* Empty states are quiet, not apologetic boxes. */
.empty-state,
.rev-empty,
.col-empty,
.tb-copy-empty {
  background: transparent;
  border: 0;
  color: var(--ink-3);
}

/* Tables: mono headers, hairline rules, no zebra. Zebra striping is a
   solution to a problem good line spacing does not have. */
table th {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink-3);
}

/* ---------------------------------------------------------------------
   4d. FILTERS, CHIPS AND TAGS

   These were the loudest things on several pages: solid accent fills on
   every selected filter and every project tag. The design puts colour
   in exactly one place — the state edge — so everything here goes back
   to ink, and "selected" is expressed physically instead.
   --------------------------------------------------------------------- */

.arc-chip,
.fbb-filters a,
.rem-tab,
.fb-type,
.in-chip {
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  box-shadow: 0 2px 0 var(--key-lip);
  transition: transform var(--press-up) var(--press-ease), box-shadow var(--press-up) ease-out;
}
.arc-chip.is-active,
.fbb-filters a.is-on,
.rem-tab.is-on,
.fb-type.is-on,
.in-chip.is-active {
  transform: translateY(2px);
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--ink);
  font-weight: 600;
  box-shadow: 0 0 0 var(--key-lip), inset 0 2px 4px var(--key-in);
}

/* A project tag names a thing; it is not an alert. The archive drew
   these as solid fills in six project colours — the loudest elements on
   a page that is otherwise somebody's work history. The project keeps
   its colour, as a dot: identity without shouting. The [data-color]
   selectors are matched exactly, because the sheet that painted them
   uses that specificity. */
.arc-badge,
.task-flag,
.pill--e {
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
  font-weight: 600;
}

.arc-badge--proj,
.arc-badge--proj[data-color] {
  position: relative;
  padding-left: 19px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
}
.arc-badge--proj::before {
  content: '';
  position: absolute;
  left: 7px;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  border-radius: 50%;
  background: var(--proj-terracotta);
}
.arc-badge--proj[data-color="sage"]::before  { background: var(--proj-sage); }
.arc-badge--proj[data-color="ocean"]::before { background: var(--proj-ocean); }
.arc-badge--proj[data-color="plum"]::before  { background: var(--proj-plum); }
.arc-badge--proj[data-color="gold"]::before  { background: var(--proj-gold); }
.arc-badge--proj[data-color="slate"]::before { background: var(--proj-slate); }

/* =====================================================================
   5. THE STAMP — the moment the whole tool is built around

   The only animation in the product allowed to run longer than 120ms,
   because it is the only one a person will watch on purpose. It lands
   like a rubber stamp: fast in, a hair of overshoot, no bounce, no
   confetti. Points and badges reward volume — the fastest way to win a
   points system is to split one task into six — so the reward here is
   the work visibly leaving the page, which stays true in month nine.
   ===================================================================== */

@keyframes tactile-stamp {
  0%   { transform: rotate(-16deg) scale(1.9); opacity: 0; }
  55%  { transform: rotate(-6deg)  scale(.96); opacity: 1; }
  100% { transform: rotate(-7deg)  scale(1);   opacity: .62; }
}

.stamp-done {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .2em;
  color: var(--ok);
  border: 2px solid var(--ok);
  border-radius: 4px;
  padding: 2px 7px;
  animation: tactile-stamp 220ms var(--press-ease) both;
}

/* The tick itself: the checkbox presses in rather than lighting up. */
.task-check:active { transform: translateY(1px); }
.task-check:checked {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .25);
  /* The row is re-rendered when it is ticked, so this fires exactly
     when somebody finishes something — and not on a page load, because
     a finished row from yesterday arrives already checked in markup
     that is only built once. */
  animation: tactile-tick 200ms var(--press-ease) both;
}
@keyframes tactile-tick {
  0%   { transform: scale(1.6); }
  60%  { transform: scale(.94); }
  100% { transform: scale(1); }
}

/* =====================================================================
   6. MACHINE — where the model speaks

   Nothing a model wrote is ever allowed to look like something a
   colleague wrote. No sparkle icon, no purple gradient, no label to
   read: the material is simply different from every other surface.
   The travelling light on the edge means "thinking", and it is the only
   loop in the product — so a loop always means "still working".
   ===================================================================== */

.machine {
  position: relative;
  overflow: hidden;
  background: linear-gradient(var(--mach), var(--mach-2));
  border: 1px solid var(--mach-line);
  border-radius: var(--radius-sm);
  color: var(--mach-ink);
}
.machine .machine-edge {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--mach-lit);
}
.machine .machine-edge.is-busy { background: #2c3f57; }
.machine .machine-edge.is-busy::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(transparent, var(--mach-lit), transparent);
  animation: tactile-travel 1.1s linear infinite;
}
@keyframes tactile-travel {
  0%   { transform: translateY(-100%); }
  100% { transform: translateY(100%); }
}
.machine-dim { color: var(--mach-ink-2); }

/* A key on graphite is still a key — it just belongs to the machine. */
.machine .btn,
.machine .ghost-btn,
.machine button.key {
  border-color: var(--mach-line);
  background: linear-gradient(#3b3d46, #2c2e35);
  color: var(--mach-ink);
  box-shadow: 0 3px 0 #191a1f, inset 0 1px 0 rgba(255, 255, 255, .12);
}
.machine .btn:active,
.machine .ghost-btn:active {
  box-shadow: 0 0 0 #191a1f, inset 0 2px 5px rgba(0, 0, 0, .6);
}

/* The dog-ear: a suggestion a person kept becomes ordinary paper with
   one folded graphite corner, so six months later you can still tell
   where it came from — while the author of record stays the person who
   pressed the button. */
.from-machine { position: relative; }
.from-machine::after {
  content: '';
  position: absolute;
  right: 0; top: 0;
  width: 0; height: 0;
  border-top: 14px solid var(--mach);
  border-left: 14px solid transparent;
  pointer-events: none;
}

/* =====================================================================
   6b. THE MACHINE, WHERE IT ACTUALLY APPEARS

   The design's rule is that nothing a model wrote may look like
   something a colleague wrote. Until now that material existed in the
   stylesheet and was used on exactly one page. These are the surfaces
   in the product where a model is the author: the meeting assistant,
   the drafted message, the written handover, and the completion
   pre-check. All graphite, all with the lit edge, in both themes —
   the material is the signal, so it cannot change with the theme.
   ===================================================================== */

.mtg-ai,
#cResult,
.kt-doc,
.td-ai {
  position: relative;
  overflow: hidden;
  background: linear-gradient(var(--mach), var(--mach-2));
  border: 1px solid var(--mach-line);
  border-radius: var(--radius-sm);
  color: var(--mach-ink);
  padding: 16px 18px 16px 21px;
}
.mtg-ai::before,
#cResult::before,
.kt-doc::before,
.td-ai::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--mach-lit);
}

/* Anything inside a machine panel belongs to the machine. */
.mtg-ai h2, #cResult h2, .kt-doc h2, .td-ai h2,
.mtg-ai h3, #cResult h3, .kt-doc h3,
.mtg-ai strong, #cResult strong, .kt-doc strong, .td-ai strong { color: var(--mach-ink); }
.mtg-ai p, #cResult p, .kt-doc p, .td-ai p,
.mtg-ai li, #cResult li, .kt-doc li { color: var(--mach-ink-2); }
.mtg-ai .ghost-btn, #cResult .ghost-btn, .kt-doc .ghost-btn, .td-ai .ghost-btn,
.mtg-ai .btn, #cResult .btn {
  border-color: var(--mach-line);
  background: linear-gradient(#3b3d46, #2c2e35);
  color: var(--mach-ink);
  box-shadow: 0 3px 0 #191a1f, inset 0 1px 0 rgba(255, 255, 255, .12);
}
.mtg-ai textarea, #cResult textarea, .mtg-ai input, #cResult input {
  background: rgba(255, 255, 255, .05);
  border-color: var(--mach-line);
  color: var(--mach-ink);
  box-shadow: none;
}

/* Buttons that hand work to a model are the machine too — a graphite
   key with the lit edge, not the accent key. The accent is reserved
   for the thing a PERSON came to the page to do; asking a model to
   draft something is a different kind of act and should not compete
   with it. */
#hGo,
#cGo,
#aiExtract,
#aiSummarize,
#aiValidate,
.js-ai-action {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--mach-line);
  background: linear-gradient(#3b3d46, #2c2e35);
  color: var(--mach-ink);
  box-shadow: 0 3px 0 #191a1f, inset 0 1px 0 rgba(255, 255, 255, .12);
}
#hGo::before,
#cGo::before,
#aiExtract::before,
#aiSummarize::before,
#aiValidate::before,
.js-ai-action::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--mach-lit);
}
#hGo:active,
#cGo:active,
#aiExtract:active,
#aiSummarize:active,
.js-ai-action:active {
  transform: translateY(3px);
  box-shadow: 0 0 0 #191a1f, inset 0 2px 5px rgba(0, 0, 0, .6);
}

/* The rephrase key on the board: the one place the machine is a single
   button rather than a panel. Graphite with the lit edge on its left,
   so it reads as the machine even at 40px square. */
.tb-add-ai,
.add-ai {
  position: relative;
  overflow: hidden;
  background: linear-gradient(#3b3d46, #2c2e35);
  border-color: var(--mach-line);
  color: var(--mach-ink);
}
.tb-add-ai::before,
.add-ai::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--mach-lit);
}
.tb-add-ai:hover, .add-ai:hover { color: #fff; border-color: var(--mach-lit); }

/* =====================================================================
   6c. HINTS

   What an icon does, in the product's own material rather than the
   operating system's. The machine speaking for itself, so it is
   graphite with the lit edge like everything else that does.
   ===================================================================== */
.hint-tip {
  position: fixed;
  z-index: 9999;
  max-width: 260px;
  padding: 6px 10px 7px 12px;
  border: 1px solid var(--mach-line);
  border-radius: 7px;
  background: linear-gradient(var(--mach), var(--mach-2));
  color: var(--mach-ink);
  font-family: var(--font-body);
  font-size: 12px;
  line-height: 1.35;
  letter-spacing: .01em;
  pointer-events: none;
  box-shadow: 0 8px 20px -12px rgba(0, 0, 0, .7);
  opacity: 0;
  transform: translateY(3px);
  transition: opacity 90ms ease-out, transform 90ms ease-out;
}
.hint-tip::before {
  content: '';
  position: absolute;
  left: 0; top: 5px; bottom: 5px;
  width: 2px;
  border-radius: 2px;
  background: var(--mach-lit);
}
.hint-tip.is-in { opacity: 1; transform: translateY(0); }
.hint-tip.is-below { transform: translateY(-3px); }
.hint-tip.is-below.is-in { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .hint-tip { transition: none; transform: none; }
}

/* A block of code is the machine's own handwriting, so it is drawn in
   the machine's material rather than as a grey box. */
.api-code {
  margin: 10px 0 12px;
  padding: 13px 15px 13px 18px;
  position: relative;
  overflow-x: auto;
  background: linear-gradient(var(--mach), var(--mach-2));
  border: 1px solid var(--mach-line);
  border-radius: var(--radius-sm);
  color: var(--mach-ink);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.65;
}
.api-code::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--mach-lit);
}
.api-code code { font: inherit; color: inherit; white-space: pre; }

/* =====================================================================
   7. RESPECT THE SETTING

   Someone who has switched motion off still gets the press — they just
   get it without the travel. The shading carries it on its own.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  button, .btn, .ghost-btn, .auth-primary, .icon-btn, .admin-btn, a.btn,
  input[type="submit"], input[type="button"] {
    transition: box-shadow 1ms linear;
  }
  button:active, .btn:active, .ghost-btn:active, .auth-primary:active,
  .icon-btn:active, .admin-btn:active, a.btn:active,
  .is-held, [aria-pressed="true"] {
    transform: none;
  }
  .stamp-done { animation: none; opacity: .62; transform: rotate(-7deg); }
  .machine .machine-edge.is-busy::after { animation: none; background: var(--mach-lit); }
}

/* Print: none of this means anything on paper, and a lip renders as a
   grey smear. */
@media print {
  .btn, .ghost-btn, .auth-primary, .admin-btn, .panel, .admin-card,
  .set-card, .tile, .card { box-shadow: none !important; }
}
