/* ==========================================================
   ATOVIVA - style.css
   All styling for index.html and app.html.
   ========================================================== */

/* A CSS variable is a named value, like --accent. The rules below use
   var(--accent) instead of repeating the colour code, so changing a value
   here once restyles the whole app. */
:root {
  /* Warm paper ground, off-white cards and near-black "ink" for text and
     strong lines. The sidebar stays dark. */
  --bg-app: #f3f2ee;
  --bg-surface: #fcfbf9;
  --bg-sidebar: #1b1d2a;

  --text-main: #1c1c22;
  --text-muted: #5c5b63;
  --text-on-dark: #e9eaf2;

  /* --accent-deep is for accent-coloured text on a light tint, where the
     normal accent is too faint to read. --accent-on-dark is the same for
     text on the dark sidebar colour. */
  --accent: #5b5bd6;
  --accent-deep: #3a3aa6;
  --accent-soft: #e9e9f9;
  --accent-on-dark: #a8a8f0;

  /* --border is a thin, quiet line. --line-strong is the ink line that
     marks the edges that matter: page headers, sections, dialogs. */
  --border: #d6d4ce;
  --line-strong: var(--text-main);

  --ok: #15703c;
  --warn: #8a5d00;
  --danger: #b3261e;

  /* A condensed font makes headings, buttons and labels narrower, so more
     fits on a line. No font is downloaded: each computer uses the first one
     in the list it already has (Windows: Bahnschrift, iPhone: Avenir Next
     Condensed, Android: Roboto Condensed). */
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-heading: "Bahnschrift Condensed", "Bahnschrift SemiCondensed", "Avenir Next Condensed", "Roboto Condensed", "Arial Narrow", sans-serif-condensed, system-ui, sans-serif;

  /* Nearly square corners. The solid "hard" shadow sits down and to the
     right, like a printed object, and has no blur. */
  --radius: 4px;
  --shadow-hard: 3px 3px 0 var(--line-strong);
  --shadow-hard-large: 6px 6px 0 var(--line-strong);

  /* Every gap in this file is one of these six steps, all worked out from
     --space. calc() does the maths, so changing --space rescales them all. */
  --space: 16px;
  --space-xs: calc(var(--space) / 4);     /* 4px */
  --space-s: calc(var(--space) / 2);      /* 8px */
  --space-m: calc(var(--space) * 0.75);   /* 12px */
  --space-l: calc(var(--space) * 1.5);    /* 24px */
  --space-xl: calc(var(--space) * 2);     /* 32px */
}


/* ---------- Reset and base ---------- */

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

body {
  margin: 0;
  font-family: var(--font-body);
  background: var(--bg-app);
  color: var(--text-main);
  line-height: 1.5;
}

h1,
h2,
h3 {
  font-family: var(--font-heading);
  font-weight: 700;
  letter-spacing: 0.01em;
}

a {
  color: var(--accent-deep);
}

/* The hidden attribute must always hide. Classes like .btn set "display",
   which would otherwise beat it and keep a hidden button on screen.
   !important makes this rule win over any class. */
[hidden] {
  display: none !important;
}

/* Keyboard users move through the page with the Tab key. This outline is
   the only way they can see which link, button or field they are on, so
   it must never be hidden. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}


/* ---------- Reusable pieces ---------- */

.card {
  padding: var(--space);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* Removes the extra space above the first and below the last thing in a
   card, so the card's own padding is the only gap at its edges. */
.card > :first-child {
  margin-top: 0;
}

.card > :last-child {
  margin-bottom: 0;
}

/* Buttons use the condensed heading font, so three of them fit side by
   side on a phone. 8px above and below keeps each one about 40px tall:
   easy to hit with a thumb. */
.btn {
  display: inline-block;
  padding: var(--space-s) var(--space);
  background: var(--bg-surface);
  color: var(--text-main);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  font-family: var(--font-heading);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms, border-color 120ms, color 120ms, box-shadow 100ms, transform 100ms;
}

.btn:hover {
  background: var(--accent-soft);
}

/* The primary button is the one solid object on the page: accent fill,
   ink edge and a hard shadow. Pressing it moves it into its shadow. */
.btn-primary {
  background: var(--accent);
  color: #ffffff;
  box-shadow: var(--shadow-hard);
}

/* color-mix blends 85% of the accent with 15% black. The hover colour is a
   little darker, and it still follows --accent if you change it. */
.btn-primary:hover {
  background: color-mix(in srgb, var(--accent) 85%, black);
}

.btn-primary:active,
.btn-danger:active {
  box-shadow: none;
  transform: translate(3px, 3px);
}

.btn-quiet {
  background: transparent;
  border-color: transparent;
  color: var(--accent-deep);
}

.btn-quiet:hover {
  background: var(--accent-soft);
}

.btn-danger {
  background: var(--danger);
  color: #ffffff;
  box-shadow: var(--shadow-hard);
}

.btn-danger:hover {
  background: color-mix(in srgb, var(--danger) 85%, black);
}

/* A disabled button turns grey instead of see-through. See-through text
   was too faint to read (3.8 to 1); grey text on the paper colour is 6 to 1. */
.btn:disabled {
  background: var(--bg-app);
  border-color: var(--border);
  color: var(--text-muted);
  box-shadow: none;
  transform: none;
  cursor: not-allowed;
}

/* A small square label in the condensed font, in capitals. */
.badge {
  display: inline-block;
  padding: 0 var(--space-s);
  background: var(--accent-soft);
  color: var(--accent-deep);
  border: 1px solid transparent;
  border-radius: 2px;
  font-family: var(--font-heading);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-bottom: var(--space);
}

.field label {
  font-weight: 600;
}

/* The edge uses --text-muted, not --border: an empty box needs a clearly
   visible outline so people can see where to type. */
.field input,
.field select,
.field textarea {
  width: 100%;
  padding: var(--space-s) var(--space-m);
  background: var(--bg-surface);
  color: var(--text-main);
  border: 1px solid var(--text-muted);
  border-radius: var(--radius);
  font: inherit;
}

/* Only taller, never wider, so a dragged text box can't push the page
   wider than a phone screen. */
.field textarea {
  resize: vertical;
}

/* Error text under a field. It takes up no space until it has a message. */
.field-error {
  margin: 0;
  color: var(--danger);
  font-size: 0.9rem;
}

.field-error:empty {
  display: none;
}

/* The page script marks a wrong field with aria-invalid="true". Screen
   readers announce that, and this rule gives the field a red edge. */
.field [aria-invalid="true"] {
  border-color: var(--danger);
}

/* Small grey helper text: hints, counters and notes near form fields. */
.hint {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin-top: var(--space-s);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space);
}

.notice {
  margin: var(--space) 0;
  padding: var(--space-m) var(--space);
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-left-width: 4px;
  border-radius: var(--radius);
}

/* The workspace box holds two short paragraphs: a small gap between them,
   none around the outside, so the box's own padding sets the edges. */
.notice p {
  margin: 0;
}

.notice p + p {
  margin-top: var(--space-xs);
}

/* A solid, calm panel with the message in the heading font, so an empty
   list looks finished on purpose. (A dashed edge looked like something
   had failed to load.) */
.empty-state {
  margin: 0;
  padding: var(--space-xl) var(--space);
  background: var(--bg-surface);
  color: var(--text-main);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-family: var(--font-heading);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
}


/* ---------- Workspace layout (app.html) ---------- */

.app-layout {
  display: flex;
  min-height: 100vh;
}

/* Sticky and exactly one screen tall, so the menu stays in view while the
   main column scrolls. */
.sidebar {
  position: sticky;
  top: 0;
  flex-shrink: 0;
  width: 220px;
  height: 100vh;
  overflow-y: auto;
  padding: var(--space);
  background: var(--bg-sidebar);
  color: var(--text-on-dark);
}

.wordmark {
  margin: 0 0 var(--space-l);
  padding: 0 var(--space-m);
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.08em;
}

.nav-group + .nav-group {
  margin-top: var(--space-l);
}

/* The HTML says "Plan" and CSS makes it look like PLAN, so screen readers
   read a normal word instead of spelling out capital letters. */
.nav-heading {
  margin: 0 0 var(--space-xs);
  padding: 0 var(--space-m);
  font-family: var(--font-heading);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-on-dark);
}

.nav-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 8px above and below makes each link about 40px tall: easy to hit with
   a thumb. */
.nav-link {
  display: block;
  padding: var(--space-s) var(--space-m);
  color: var(--text-on-dark);
  border-radius: var(--radius);
  font-family: var(--font-heading);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-decoration: none;
  text-transform: uppercase;
}

.nav-link:hover {
  background: color-mix(in srgb, var(--bg-sidebar) 85%, white);
}

.nav-link.is-active {
  background: var(--accent);
  color: #ffffff;
}

.main-column {
  flex: 1;
  min-width: 0;
  padding: var(--space-xl);
}

/* The ink line under the title is the one strong line on each page. */
.page-header {
  padding-bottom: var(--space);
  border-bottom: 2px solid var(--line-strong);
}

.page-header h1 {
  margin: 0;
  font-size: clamp(2rem, 5vw, 2.75rem);
  line-height: 1;
  text-transform: uppercase;
}

.page-header p {
  margin: var(--space-s) 0 0;
  color: var(--text-muted);
}


/* ---------- Landing page (index.html) ---------- */

/* Keeps each section's content at a comfortable width in the middle of the
   screen, with side padding so text never touches the edge on a phone. */
.container {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 var(--space);
}

.site-header {
  background: var(--bg-app);
  border-bottom: 2px solid var(--line-strong);
}

.site-header .container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m) var(--space);
  padding-top: var(--space-m);
  padding-bottom: var(--space-m);
}

.site-header .wordmark {
  margin: 0;
  padding: 0;
}

.hero {
  padding: calc(var(--space) * 5) 0 calc(var(--space) * 3);
  border-bottom: 2px solid var(--line-strong);
}

/* clamp(smallest, preferred, largest): the headline grows with the screen
   (8vw is 8% of its width) but stays between 2.5rem and 5.5rem. */
.hero h1 {
  max-width: 900px;
  margin: 0;
  font-size: clamp(2.5rem, 8vw, 5.5rem);
  line-height: 0.95;
  text-transform: uppercase;
}

.hero-subtitle {
  max-width: 640px;
  margin: var(--space-l) 0 0;
  color: var(--text-muted);
  font-size: 1.125rem;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  margin-top: var(--space-l);
}

/* The honest "early prototype" line sits in a small ink-edged box, so it
   reads as a label, not small print. */
.hero-note {
  display: inline-block;
  margin: var(--space-l) 0 0;
  padding: var(--space-xs) var(--space-m);
  border: 1px solid var(--line-strong);
  font-size: 0.9rem;
}

.landing-section {
  padding: calc(var(--space) * 4) 0;
}

/* Sections are divided by ink lines instead of changes of colour. */
.landing-section + .landing-section {
  border-top: 2px solid var(--line-strong);
}

.landing-section h2 {
  margin: 0 0 var(--space-l);
  font-size: clamp(2rem, 4.4vw, 3.25rem);
  line-height: 1;
  text-transform: uppercase;
}

.landing-section h3 {
  margin: 0 0 var(--space-s);
  font-size: 1.375rem;
  line-height: 1.1;
  text-transform: uppercase;
}

.landing-section h3 + p {
  margin-top: 0;
}

/* The three feature cards right after the hero are ink-edged objects with
   a hard shadow, numbered 01, 02, 03 by a CSS counter (a number CSS counts
   up by itself). The text after "/" is what screen readers say: nothing,
   because the number is only for the eye. */
.hero + .landing-section .grid {
  counter-reset: feature;
  gap: var(--space-l);
}

.hero + .landing-section .card {
  padding: var(--space-l);
  border: 2px solid var(--line-strong);
  box-shadow: var(--shadow-hard-large);
}

.hero + .landing-section .card::before {
  counter-increment: feature;
  content: counter(feature, decimal-leading-zero);
  content: counter(feature, decimal-leading-zero) / "";
  display: block;
  margin-bottom: var(--space-m);
  color: var(--accent);
  font-family: var(--font-heading);
  font-size: 3rem;
  font-weight: 700;
  line-height: 1;
}

/* Studio services are a side offer, not the product, so they get a dark
   band in the sidebar colour and plain outlined tiles instead of cards. */
.studio-band {
  background: var(--bg-sidebar);
  color: var(--text-on-dark);
}

.eyebrow {
  margin: 0 0 var(--space-s);
  color: var(--accent-deep);
  font-family: var(--font-heading);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.studio-band .eyebrow {
  color: var(--accent-on-dark);
}

.studio-intro {
  max-width: 640px;
}

.studio-list {
  margin: var(--space-l) 0 0;
  padding: 0;
  list-style: none;
}

.studio-list li {
  padding: var(--space-m) var(--space);
  border: 1px solid color-mix(in srgb, var(--text-on-dark) 40%, var(--bg-sidebar));
  border-radius: var(--radius);
}

/* Video cards stay between 220px and 300px wide, so the tall 9:16 boxes
   never grow huge on a big screen. */
.portfolio-grid {
  grid-template-columns: repeat(auto-fit, minmax(220px, 300px));
  justify-content: center;
}

/* aspect-ratio keeps the box 9 wide by 16 tall, the shape of a phone
   video, at every screen size, without a fixed pixel height. position:
   relative lets the video or embed inside be laid exactly over the box. */
.video-frame {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 9 / 16;
  margin-bottom: var(--space-m);
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  font-family: var(--font-heading);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-align: center;
  text-transform: uppercase;
}

/* The player stays hidden and the grey box shows, until the script in
   index.html has checked that the file exists and added .has-video.
   contain shows the whole video, with dark bars if it is not 9:16. */
.portfolio-video {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000000;
}

.video-frame.has-video .portfolio-video {
  display: block;
}

.video-frame.has-video .video-placeholder {
  display: none;
}

/* A YouTube or Instagram embed (see README.md) fills the box the same way.
   It has no placeholder, because it is only added by hand. */
.video-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* The contact form is the page's last call to action, so it gets the
   heaviest frame: an ink edge and a shadow in the accent colour. */
.contact-area {
  max-width: 560px;
}

.contact-area .card {
  padding: var(--space-l);
  border: 2px solid var(--line-strong);
  box-shadow: 6px 6px 0 var(--accent);
}

.site-footer {
  padding: var(--space-xl) 0;
  border-top: 2px solid var(--line-strong);
  color: var(--text-muted);
  font-size: 0.9rem;
}

.site-footer .container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-s) var(--space);
}

.site-footer p {
  margin: 0;
}


/* ---------- Composer (built by app.js inside #view) ---------- */

.composer-form {
  max-width: 720px;
}

.composer-form h2 {
  margin: 0 0 var(--space);
  font-size: 1.5rem;
  line-height: 1.1;
  text-transform: uppercase;
}

/* The fields already have space below them, so the grid only needs a gap
   between its two columns, not between its rows. */
.composer-form .grid {
  gap: 0 var(--space);
}

.char-counter.is-warn {
  color: var(--warn);
}

.char-counter.is-danger {
  color: var(--danger);
}


/* ---------- Post library (built by app.js inside #view) ---------- */

.filter-bar {
  margin-bottom: var(--space);
}

.status-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin-bottom: var(--space);
}

/* A pressed toggle button (the selected status tab, or the chosen calendar
   view) is filled with the accent colour. aria-pressed="true" is also what
   tells screen readers which one is selected. */
.btn[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--line-strong);
  color: #ffffff;
}

.filter-controls {
  gap: var(--space-m);
}

.filter-controls .field {
  margin-bottom: 0;
}

.clear-filters-button {
  margin-top: var(--space-m);
}

.post-list {
  display: grid;
  gap: var(--space-s);
}

/* Every card list shares these classes: posts, videos, clients and notes.
   anywhere lets very long words or links break onto the next line, so they
   can never push a card wider than a phone screen. */
.post-card {
  overflow-wrap: anywhere;
}

/* In the post library on a wide screen, Edit, Duplicate and Delete move to
   a column on the right instead of taking a row of their own, so each card
   is shorter and more posts fit on the screen. Every other part of the
   card stays in the left column. On phones (see the end of this file) the
   buttons go back underneath. */
@media (min-width: 900px) {
  #post-list > .post-card {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space);
  }

  #post-list > .post-card > * {
    grid-column: 1;
  }

  #post-list > .post-card > .form-actions {
    grid-column: 2;
    grid-row: 1 / span 4;
    align-self: start;
    margin-top: 0;
  }
}

.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s) var(--space-m);
  margin-bottom: var(--space-s);
}

.post-platform {
  font-weight: 600;
}

/* pre-line keeps the line breaks I typed in a caption. */
.post-caption {
  margin: 0 0 var(--space-xs);
  white-space: pre-line;
}

/* Status badges for posts, videos and clients. Each status is told apart
   three ways, so nobody depends on colour alone:
     1. the word itself (Draft, Scheduled...),
     2. a symbol in front of it, added by CSS below,
     3. a colour: grey = not started, amber = in progress, purple = on its
        way, green = done, red = failed.
   Each group only sets --status-colour. The shared rule after them uses it
   for the text, the edge and (mixed 10% with white) a light background.
   Type, category and tag badges keep the plain .badge look. */
.badge.status-draft,
.badge.status-idea,
.badge.status-not_contacted {
  --status-colour: var(--text-muted);
  border-style: dashed;
}

.badge.status-editing,
.badge.status-project {
  --status-colour: var(--warn);
}

.badge.status-scheduled,
.badge.status-ready,
.badge.status-contacted,
.badge.status-replied {
  --status-colour: var(--accent-deep);
}

.badge.status-published,
.badge.status-finished,
.badge-delivered {
  --status-colour: var(--ok);
}

.badge.status-failed {
  --status-colour: var(--danger);
}

/* "Not interested" is not a failure, so it stays grey and quiet. */
.badge.status-not_interested {
  --status-colour: var(--text-muted);
}

/* [class*="status-"] means "any badge whose class contains status-". */
.badge[class*="status-"],
.badge-delivered {
  background: color-mix(in srgb, var(--status-colour) 10%, white);
  color: var(--status-colour);
  border-color: var(--status-colour);
}

/* The symbols. Each content line is written twice: browsers that know the
   newer form (after "/") keep the symbol silent for screen readers, which
   already read the word; older browsers use the first line. */
.badge[class*="status-"]::before,
.badge-delivered::before {
  margin-right: var(--space-xs);
}

.badge.status-draft::before,
.badge.status-idea::before,
.badge.status-not_contacted::before {
  content: "○";
  content: "○" / "";
}

.badge.status-editing::before,
.badge.status-project::before {
  content: "◐";
  content: "◐" / "";
}

.badge.status-scheduled::before,
.badge.status-ready::before,
.badge.status-contacted::before,
.badge.status-replied::before {
  content: "●";
  content: "●" / "";
}

.badge.status-published::before,
.badge.status-finished::before,
.badge-delivered::before {
  content: "✓";
  content: "✓" / "";
}

.badge.status-failed::before {
  content: "!";
  content: "!" / "";
}

.badge.status-not_interested::before {
  content: "–";
  content: "–" / "";
}

.empty-state p {
  margin: 0;
}

.empty-state .btn {
  margin-top: var(--space);
}


/* ---------- Calendar (built by app.js inside #view) ---------- */

.calendar-toolbar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-s);
  margin-bottom: var(--space);
}

.calendar-nav,
.calendar-view-toggle {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
}

.calendar h2 {
  margin: 0 0 var(--space-xs);
  font-size: 1.5rem;
  line-height: 1.1;
  text-transform: uppercase;
}

.calendar-note {
  margin-bottom: var(--space);
}

/* Seven equal columns, Monday to Sunday. minmax(0, 1fr) lets a column get
   narrower than a long chip instead of stretching the whole grid. */
.calendar-weekdays,
.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--space-xs);
}

.calendar-weekdays {
  margin-bottom: var(--space-xs);
  color: var(--text-muted);
  font-family: var(--font-heading);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-align: center;
  text-transform: uppercase;
}

.calendar-grid {
  margin: 0;
  padding: 0;
  list-style: none;
}

.calendar-day {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-height: 96px;
  padding: var(--space-s);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* Today and future days start a new post when clicked. */
.calendar-day[data-new-post-date] {
  cursor: pointer;
}

.calendar-day.is-past {
  background: var(--bg-app);
}

.calendar-day.is-today {
  border: 2px solid var(--accent);
}

.calendar-day-number {
  align-self: flex-start;
  padding: 0 var(--space-xs);
  background: none;
  border: 0;
  border-radius: 2px;
  color: var(--text-main);
  font: inherit;
  font-family: var(--font-heading);
  font-weight: 700;
}

button.calendar-day-number {
  cursor: pointer;
}

/* Each platform class below only sets --chip-colour. The chip uses it twice:
   for the stripe on the left, and mixed with white for a light tint. The
   text stays dark, so it is easy to read on every platform colour. */
.calendar-chip {
  --chip-colour: var(--text-muted);
  display: block;
  overflow: hidden;
  padding: var(--space-xs) var(--space-s);
  background: color-mix(in srgb, var(--chip-colour) 14%, white);
  border-left: 4px solid var(--chip-colour);
  border-radius: 2px;
  color: var(--text-main);
  font-size: 0.8rem;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calendar-chip.platform-instagram {
  --chip-colour: #c13584;
}

.calendar-chip.platform-tiktok {
  --chip-colour: #111111;
}

.calendar-chip.platform-youtube {
  --chip-colour: #cc0000;
}

.calendar-chip.platform-facebook {
  --chip-colour: #1877f2;
}

.calendar-chip.platform-linkedin {
  --chip-colour: #0a66c2;
}

.calendar-more {
  align-self: flex-start;
  padding: 0;
  background: none;
  border: 0;
  color: var(--accent-deep);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
}

.calendar-list h3 {
  margin: var(--space) 0 var(--space-s);
  font-size: 1.125rem;
  text-transform: uppercase;
}

.calendar-list ul {
  display: grid;
  gap: var(--space-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* In the list there is room, so a chip may wrap onto several lines. */
.calendar-list .calendar-chip {
  padding: var(--space-s) var(--space-m);
  font-size: 0.9rem;
  white-space: normal;
  overflow-wrap: anywhere;
}


/* ---------- Overview (built by app.js inside #view) ---------- */

.quick-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  margin-bottom: var(--space-l);
}

.section-heading {
  margin: 0 0 var(--space-xs);
  font-size: 1.375rem;
  line-height: 1.1;
  text-transform: uppercase;
}

.overview-section {
  margin-bottom: var(--space);
}

/* As many cards of at least 130px as fit in a row; the rest wrap onto the
   next row. That is all seven on a laptop and two per row at 375px. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: var(--space-m);
  margin: var(--space-m) 0 0;
  padding: 0;
  list-style: none;
}

.stat-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* Big condensed numbers, like the figures on a spec sheet. */
.stat-value {
  font-family: var(--font-heading);
  font-size: 2.5rem;
  font-weight: 700;
  line-height: 1;
}

.stat-label {
  color: var(--text-muted);
  font-size: 0.9rem;
  line-height: 1.3;
}

/* Side by side when each panel can be at least 300px wide, stacked when
   not. min(100%, 300px) stops a panel being wider than a phone screen. */
.overview-panels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  align-items: start;
  gap: var(--space);
  margin-bottom: var(--space);
}

.overview-list {
  display: grid;
  gap: var(--space-s);
  margin: var(--space-m) 0 0;
  padding: 0;
  list-style: none;
}

/* The whole row is one link, so it is easy to hit on a phone. */
.overview-post {
  display: flex;
  flex-direction: column;
  padding: var(--space-s) var(--space-m);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-main);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.overview-post:hover {
  background: var(--accent-soft);
  border-color: var(--accent);
}

.overview-post-caption {
  font-weight: 600;
}

/* Inside a panel the empty message needs less height than on a full page. */
.overview-panel .empty-state {
  margin-top: var(--space-m);
  padding: var(--space-l) var(--space);
}

/* A heading with a Sample badge next to it, wrapping on narrow screens. */
.panel-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s);
  margin-bottom: var(--space-xs);
}

.panel-header .section-heading {
  margin: 0;
}


/* ---------- Sample data (Overview goals and Analytics) ---------- */

/* The warning colour marks everything invented: the badge, the dashed edge
   of the goals panel and the bar at the top of Analytics. */
.badge-sample {
  background: color-mix(in srgb, var(--warn) 12%, white);
  color: var(--warn);
  border: 1px solid var(--warn);
}

.stat-card .badge-sample {
  align-self: flex-start;
  margin-bottom: var(--space-xs);
}

.sample-panel {
  border: 1px dashed var(--warn);
}

.sample-panel .stat-card {
  padding: var(--space-m);
  background: var(--bg-app);
  border-radius: var(--radius);
}

/* White text on --warn is easy to read. */
.sample-warning {
  margin: 0 0 var(--space);
  padding: var(--space-m) var(--space);
  background: var(--warn);
  color: #ffffff;
  border-radius: var(--radius);
  font-weight: 600;
}

.analytics-panel {
  margin-top: var(--space);
}

/* Seven equal columns, one per day. minmax(0, 1fr) lets them shrink on a
   phone instead of pushing the page wider. */
.bar-chart {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--space-s);
  margin: var(--space-m) 0 0;
  padding: 0;
  list-style: none;
}

.bar-chart-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
}

/* The track has a fixed height, so a bar's percentage height (set by
   app.js) means a share of these 160px. flex-end stands bars on the floor. */
.bar-chart-track {
  display: flex;
  align-items: flex-end;
  width: 100%;
  height: 160px;
  background: var(--bg-app);
  border-radius: 2px;
}

.bar-chart-bar {
  width: 100%;
  background: var(--accent);
  border-radius: 2px 2px 0 0;
}

.bar-chart-value {
  color: var(--text-muted);
  font-size: 0.75rem;
}

.bar-chart-label {
  font-family: var(--font-heading);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* If the table is ever too wide for a phone, only this box scrolls
   sideways, never the whole page. */
.table-scroll {
  margin-top: var(--space-m);
  overflow-x: auto;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
}

.data-table th,
.data-table td {
  padding: var(--space-s);
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}

.data-table th {
  border-bottom: 2px solid var(--line-strong);
  color: var(--text-muted);
  font-family: var(--font-heading);
  font-size: 0.875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Numbers line up on the right, so their digits sit under each other. */
.data-table .number-cell {
  text-align: right;
  white-space: nowrap;
}


/* ---------- Settings (built by app.js inside #view) ---------- */

.settings-section {
  margin-bottom: var(--space);
}

/* As many account cards of at least 220px as fit in a row. min(100%, 220px)
   stops a card being wider than a phone screen. */
.account-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr));
  gap: var(--space-m);
  margin: var(--space-m) 0 0;
  padding: 0;
  list-style: none;
}

.account-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  padding: var(--space-m);
  background: var(--bg-app);
  border-radius: var(--radius);
}

.account-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
}

.account-name {
  margin: 0;
  font-weight: 700;
}

.account-status {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}

/* The fields already have space below them, so the grid only needs a gap
   between its columns, the same as in the composer. */
.preferences-form .grid {
  gap: 0 var(--space);
}

/* A thin line between the three data actions, so each explanation clearly
   belongs to the button above it. */
.data-action {
  padding: var(--space-m) 0;
}

.data-action + .data-action {
  border-top: 1px solid var(--border);
}

.data-action:last-child {
  padding-bottom: 0;
}

.data-action .hint {
  margin-top: var(--space-s);
}

.storage-result {
  margin: var(--space-s) 0 0;
  font-weight: 600;
}

.storage-result:empty {
  display: none;
}

.delete-form {
  max-width: 420px;
  margin-top: var(--space-m);
  padding: var(--space-m);
  border: 1px solid var(--danger);
  border-radius: var(--radius);
}

.delete-form .field {
  margin-bottom: var(--space-s);
}

/* The import preview reuses the red-edged .delete-form box above, because
   replacing all data is just as final as deleting it. */
.import-summary {
  margin: 0 0 var(--space-m);
  font-weight: 600;
}

/* The reminder to export sits above the data buttons, in the warning
   colour, so it is seen before anything risky is pressed. */
.backup-advice {
  margin: 0 0 var(--space-xs);
  padding: var(--space-s) var(--space-m);
  border-left: 4px solid var(--warn);
  background: color-mix(in srgb, var(--warn) 8%, white);
  border-radius: var(--radius);
}

.about-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: 0 var(--space);
}

.settings-section h3 {
  margin: var(--space-m) 0 var(--space-xs);
  font-size: 1.125rem;
  text-transform: uppercase;
}

.about-grid ul {
  margin: 0;
  padding-left: var(--space-l);
}

.settings-section h3 + p {
  margin-top: 0;
}


/* ---------- Studio pages: videos, clients, notes (built by app.js) ---------- */

/* The cards, filter bar and tabs reuse the post library's classes above.
   Only what is new on these pages is styled here. */
.studio-form {
  max-width: 720px;
  margin-bottom: var(--space);
}

/* Space between the form's intro line and its first field. */
.studio-form > .hint {
  margin-bottom: var(--space-m);
}

/* The same column-only gap as the composer's grid. */
.studio-form .grid {
  gap: 0 var(--space);
}

.item-title {
  margin: 0 0 var(--space-s);
  font-size: 1.25rem;
  line-height: 1.2;
}

.item-text {
  margin: var(--space-s) 0 0;
}

.client-link {
  font-weight: 600;
}

/* The note that previews are temporary sits right above the video cards,
   in the warning colour, where the file boxes are. */
.media-note {
  margin: 0 0 var(--space);
  padding: var(--space-s) var(--space-m);
  border-left: 4px solid var(--warn);
  background: color-mix(in srgb, var(--warn) 8%, white);
  border-radius: var(--radius);
  font-size: 0.9rem;
}

/* ---- The video checklist ---- */

/* A fieldset groups the checkboxes so screen readers announce "Checklist"
   first. The browser's own border and padding are replaced by ours. */
.checklist {
  margin: var(--space-m) 0 0;
  padding: var(--space-m) 0 0;
  border: 0;
  border-top: 1px solid var(--border);
}

.checklist legend {
  float: left;
  width: 100%;
  margin-bottom: var(--space-xs);
  padding: 0;
  font-family: var(--font-heading);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.checklist-progress {
  clear: both;
  margin: 0 0 var(--space-s);
  font-size: 0.9rem;
}

/* Two divs make the bar: the grey track is the whole width, and the fill
   inside it gets its width (the percentage done) from app.js. */
.progress-track {
  height: 8px;
  margin-bottom: var(--space-s);
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--ok);
  border-radius: 2px;
}

.checklist-stages {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Each row is at least 40px tall, and the whole label can be clicked, so a
   stage is easy to tick with a thumb. The Remove button sits at the end. */
.checklist-stage {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-s);
  min-height: 40px;
  border-bottom: 1px solid var(--border);
}

.checklist-stage input[type="checkbox"] {
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--ok);
}

.checklist-stage label {
  flex: 1;
  min-width: 0;
  padding: var(--space-s) 0;
  cursor: pointer;
  overflow-wrap: anywhere;
}

.stage-time {
  font-size: 0.8rem;
}

.stage-remove {
  padding: var(--space-s) var(--space-m);
}

.add-stage-form {
  margin-top: var(--space-m);
}

.add-stage-form label {
  display: block;
  margin-bottom: var(--space-xs);
  font-weight: 600;
}

.add-stage-row {
  display: flex;
  gap: var(--space-s);
}

/* min-width: 0 lets the box shrink on a phone instead of pushing the
   button off the screen. */
.add-stage-row input {
  flex: 1;
  min-width: 0;
  padding: var(--space-s) var(--space-m);
  background: var(--bg-surface);
  color: var(--text-main);
  border: 1px solid var(--text-muted);
  border-radius: var(--radius);
  font: inherit;
}

.video-media {
  margin-top: var(--space-m);
  padding-top: var(--space-m);
  border-top: 1px solid var(--border);
}

.video-media .field {
  margin-bottom: 0;
}

/* A small preview: never wider than the card and never taller than 240px,
   so a tall phone video does not push everything else off the screen. */
.media-preview {
  display: block;
  max-width: 100%;
  max-height: 240px;
  margin: var(--space-s) 0 var(--space-xs);
  background: #000000;
  border-radius: var(--radius);
}

.pipeline-card {
  margin-bottom: var(--space);
}

/* The pipeline steps wrap onto more rows on a narrow screen. */
.pipeline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin: var(--space-s) 0 0;
  padding: 0;
  list-style: none;
}

.pipeline-step {
  padding: var(--space-xs) var(--space-m);
  background: var(--bg-app);
  border: 1px solid var(--border);
  border-radius: 2px;
  font-size: 0.9rem;
}

.pipeline-count {
  font-family: var(--font-heading);
  font-weight: 700;
}


/* ---------- Toasts and confirmation panel (made by app.js) ---------- */

/* Pinned to the bottom of the screen, above everything else. pointer-events:
   none lets clicks pass through the empty space around the toasts. */
.toast-area {
  position: fixed;
  right: var(--space);
  bottom: var(--space);
  left: var(--space);
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-s);
  pointer-events: none;
}

/* White text is easy to read on all three toast colours below. */
.toast {
  max-width: 480px;
  padding: var(--space-m) var(--space);
  color: #ffffff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-hard);
  font-weight: 600;
}

.toast-ok {
  background: var(--ok);
}

.toast-warn {
  background: var(--warn);
}

.toast-error {
  background: var(--danger);
}

/* Sits at the bottom of the screen, so it is always visible, wherever the
   button that opened it was. The ink edge and hard shadow lift it above
   the page. */
.confirm-panel {
  position: fixed;
  right: var(--space);
  bottom: var(--space);
  left: var(--space);
  z-index: 110;
  max-width: 440px;
  margin: 0 auto;
  padding: var(--space);
  background: var(--bg-surface);
  border: 2px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-hard-large);
}

.confirm-panel p {
  margin: 0 0 var(--space-m);
  font-weight: 600;
}

.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-s);
}


/* ---------- Small screens ---------- */

/* Below 820px there is no room for a side menu. The sidebar becomes a bar
   across the top that scrolls sideways, with each nav group in one row. */
@media (max-width: 820px) {
  .app-layout {
    flex-direction: column;
  }

  .sidebar {
    position: static;
    display: flex;
    align-items: center;
    gap: var(--space);
    width: auto;
    height: auto;
    overflow-x: auto;
    padding: var(--space-m) var(--space);
    white-space: nowrap;
    scrollbar-width: thin;
  }

  .wordmark {
    margin: 0;
    padding: 0;
  }

  .sidebar-nav,
  .nav-group,
  .nav-list {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
  }

  .sidebar-nav {
    gap: var(--space);
  }

  .nav-group + .nav-group {
    margin-top: 0;
  }

  .nav-heading {
    margin: 0 var(--space-xs) 0 0;
    padding: 0;
  }

  .main-column {
    padding: var(--space);
  }
}

/* Under 560px seven calendar columns cannot be read, so app.js draws only
   the list view there, and this hides the Month view / List view switch. */
@media (max-width: 559px) {
  .calendar-view-toggle {
    display: none;
  }

  /* The status tabs stay in one row that scrolls sideways, instead of
     wrapping into four rows that push the posts off the first screen.
     The small padding keeps the focus outline from being cut off. */
  .status-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding: var(--space-xs);
    margin: calc(var(--space-xs) * -1) calc(var(--space-xs) * -1) var(--space-m);
    scrollbar-width: thin;
  }

  .status-tabs .btn {
    flex-shrink: 0;
  }

  /* Two short dropdowns side by side, with the search box across the full
     width. :has() picks the field that contains the search box. "dense"
     lets the second dropdown move up next to the first. */
  .filter-controls {
    grid-template-columns: 1fr 1fr;
    grid-auto-flow: dense;
  }

  .filter-controls .field:has(input[type="search"]) {
    grid-column: 1 / -1;
  }

  .card.post-card {
    padding: var(--space-m);
  }
}
