/* Task 11 (contacto): visually hides the .est-form__trampa honeypot wrapper
   while keeping it in the DOM and reachable by bots, without using
   display:none/hidden (which some spam bots skip when filling fields).
   Task 12: append here, do not re-declare this rule when this file gets its
   full stylesheet. */
.est-form__trampa { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ===========================================================================
   es.taller.arq — page chrome and content blocks.
   Approved direction: "Portafolio cinemático" — photography first, full-bleed
   heroes with type sitting on the image, ink interstitial bands, sand accents
   on dark, and exactly one saturated teal-deep moment per page.

   Tokens live in est-tokens.css (inlined into <head> by base.html). This file
   is a normal <link>, loaded AFTER static/src/css/vendor/bootstrap-*.min.css
   so our rules win over Bootstrap's. Never restyle a Bootstrap class name:
   ours are all prefixed `est-`.

   NOT DEFINED HERE, ON PURPOSE — Task 13 owns them and appends below:
     .est-hero .est-sec__num .est-arcos .est-cta-band .est-manifesto
   (the arc-divider geometry is inlined in templates/brand/arc_divider.html;
   there is deliberately no static/src/img/est-arcos.svg).
   =========================================================================== */

/* --- 1. Dark context ------------------------------------------------------
   One class flips the semantic roles from est-tokens.css, so every component
   inside renders correctly on ink without knowing it is on ink. This is why
   components must read --est-fg / --est-acento and never --est-ink directly. */

.est-oscuro,
.est-header,
.est-footer,
.est-banda,
.est-portada,
.est-project__hero,
.est-project-grid,
.est-project-card__link,
.est-gallery {
  --est-fg:     var(--est-paper);
  --est-bg:     var(--est-ink);
  --est-muted:  color-mix(in srgb, var(--est-paper) 66%, var(--est-ink));
  --est-rule:   color-mix(in srgb, var(--est-paper) 18%, var(--est-ink));
  --est-acento: var(--est-sand);
  --est-btn-solido-bg: var(--est-paper);
  --est-btn-solido-fg: var(--est-ink);
  color: var(--est-fg);
  background-color: var(--est-bg);
}

/* --- 2. Layout primitives ------------------------------------------------- */

.est-wrap        { width: var(--est-wrap); margin-inline: auto; }
.est-wrap--ancho { width: var(--est-wrap-ancho); margin-inline: auto; }
.est-section     { padding-block: var(--est-section); }
.est-banda       { padding-block: var(--est-section); }
/* A page banner's optional lead (Proceso's intro paragraph). */
.est-banda .est-lead { margin-top: 1.5rem; max-width: 46rem; }

/* A full-bleed child of a wrapped parent. Used sparingly: the edge-to-edge
   grids get their own full-width parents in the templates instead, because
   100vw ignores the scrollbar and can add a horizontal overflow. */
.est-sangrado {
  width: 100%;
  margin-inline: 0;
}

/* --- 3. Accessibility helpers --------------------------------------------- */

/* Used by templates/partials/header.html for the studio's full name next to
   the wordmark. clip-path, not display:none — display:none would also hide it
   from screen readers, which defeats the entire point. */
.visually-hidden:not(:focus):not(:active) {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.est-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: var(--est-z-salto);
  padding: .85rem 1.4rem;
  background: var(--est-teal-deep);
  color: var(--est-paper);
  font-size: var(--est-step--1);
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
}
.est-skip:focus { left: 1rem; top: 1rem; }

/* --- 4. Typography -------------------------------------------------------- */

.est-eyebrow {
  margin: 0 0 1.15rem;
  font-size: var(--est-eyebrow-size);
  font-weight: 600;
  letter-spacing: var(--est-eyebrow-track);
  text-transform: uppercase;
  color: var(--est-acento);
  /* the last letter's tracking would otherwise push the word off-centre */
  text-indent: 0;
}
.est-eyebrow > * + * { margin-inline-start: .9rem; }

.est-h1 {
  margin: 0 0 1.25rem;
  font-size: var(--est-step-3);
  font-weight: 300;
  line-height: 1.04;
  letter-spacing: -.028em;
  text-wrap: balance;
  max-width: 20ch;
}

/* The hero headline of the approved direction: 300 weight, ~80px desktop,
   tight tracking, short measure, balanced wrapping. */
.est-h1--heroe {
  font-size: var(--est-step-4);
  letter-spacing: -.032em;
  max-width: 17ch;
  margin-bottom: 1rem;
}

.est-h2 {
  margin: 0 0 1rem;
  font-size: var(--est-step-2);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: -.022em;
  text-wrap: balance;
  max-width: 24ch;
}

.est-h3 {
  margin: 0 0 .75rem;
  font-size: var(--est-step-1);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -.012em;
}

.est-lead {
  margin: 0;
  font-size: var(--est-step-1);
  font-weight: 300;
  line-height: 1.45;
  color: var(--est-muted);
  max-width: 46ch;
}

.est-prose { max-width: 68ch; }
.est-prose > :first-child { margin-block-start: 0; }
.est-prose p { margin-block: 0 1.25em; }
.est-prose :is(h2, h3) { margin-block: 2em .6em; font-weight: 400; }
.est-prose img { border-radius: var(--est-radius-sm); }

/* --- 5. Buttons ----------------------------------------------------------- */

.est-btn {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  padding: .85rem 1.75rem;
  border: 1px solid currentColor;
  border-radius: var(--est-radius-pill);
  background: transparent;
  color: inherit;
  font-size: var(--est-step--1);
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--est-dur) var(--est-ease),
              color var(--est-dur) var(--est-ease),
              border-color var(--est-dur) var(--est-ease),
              transform var(--est-dur) var(--est-ease);
}
.est-btn:hover,
.est-btn:focus-visible { transform: translateY(-2px); }
.est-btn:hover {
  background: var(--est-btn-solido-bg);
  color: var(--est-btn-solido-fg);
  border-color: var(--est-btn-solido-bg);
}

/* Solid. Deliberately NOT teal-deep: that colour is reserved for the single
   CTA band per page, and spending it on every button would spend the one
   saturated moment the design has. */
.est-btn--primary {
  background: var(--est-btn-solido-bg);
  color: var(--est-btn-solido-fg);
  border-color: var(--est-btn-solido-bg);
}
.est-btn--primary:hover {
  background: transparent;
  color: inherit;
  border-color: currentColor;
}

/* --- 6. Header ------------------------------------------------------------
   Sticky by default, fixed over a hero.

   Sticky is right for an ordinary page: the bar occupies flow space, so the
   page's first ink band butts straight up against it with no strip of body
   background showing between them. Over a full-bleed hero that flow space is
   exactly wrong — the photograph has to reach the top edge of the viewport —
   so a page containing a [data-est-hero] element lifts the bar out of flow
   instead. Without :has() support the bar is simply sticky everywhere, which
   costs a hero its top 4.5rem and breaks nothing. */

.est-header {
  position: sticky;
  top: 0;
  z-index: var(--est-z-cabecera);
  background-color: var(--est-ink);
  transition: background-color var(--est-dur) var(--est-ease);
}

body:has([data-est-hero]) .est-header {
  position: fixed;
  inset-inline: 0;
}

/* django-cms's edit toolbar shifts <html> down, but a fixed element is
   positioned against the viewport and would slide underneath it. */
.cms-toolbar-expanded .est-header { top: 46px; }

/* Transparent over a hero. The ::before veil below still guarantees contrast
   for the white nav type, so this is safe even before the scroll script runs
   — and safe if the script never runs at all. */
body:has([data-est-hero]) .est-header:not(.est-header--solida) {
  background-color: transparent;
}

.est-header::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(18, 18, 19, .72) 0%, rgba(18, 18, 19, 0) 100%);
  opacity: 1;
  transition: opacity var(--est-dur) var(--est-ease);
  pointer-events: none;
}
.est-header--solida::before { opacity: 0; }

.est-header__interior {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.5rem);
  width: var(--est-wrap-ancho);
  margin-inline: auto;
  min-height: var(--est-cabecera);
}

.est-header__logo {
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  margin-inline-end: auto;
  text-decoration: none;
  color: inherit;
}
.est-header__marca { width: 30px; height: 30px; flex: none; }
.est-header__wordmark {
  font-size: var(--est-step-0);
  font-weight: 500;
  letter-spacing: .04em;
}

.est-header__acciones {
  display: flex;
  align-items: center;
  gap: clamp(.75rem, 2vw, 1.5rem);
}

/* Hamburger. Hidden on desktop, and hidden altogether with scripting off — a
   dead control is worse than no control. base.html's <noscript> block takes it
   away and leaves the navigation permanently expanded instead. */
.est-header__menu {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 1px solid var(--est-rule);
  border-radius: var(--est-radius-pill);
  background: transparent;
  color: inherit;
  cursor: pointer;
}
.est-header__menu-barras,
.est-header__menu-barras::before,
.est-header__menu-barras::after {
  display: block;
  width: 16px;
  height: 1px;
  background: currentColor;
  transition: transform var(--est-dur) var(--est-ease),
              opacity var(--est-dur) var(--est-ease);
}
.est-header__menu-barras::before,
.est-header__menu-barras::after { content: ""; position: relative; }
.est-header__menu-barras::before { top: -5px; }
.est-header__menu-barras::after  { top: 4px; }
.est-header__menu[aria-expanded="true"] .est-header__menu-barras { background: transparent; }
.est-header__menu[aria-expanded="true"] .est-header__menu-barras::before { transform: translateY(5px) rotate(45deg); }
.est-header__menu[aria-expanded="true"] .est-header__menu-barras::after  { transform: translateY(-4px) rotate(-45deg); }

/* --- 7. Navigation -------------------------------------------------------- */

.est-nav__lista {
  display: flex;
  align-items: center;
  gap: clamp(1.1rem, 2.2vw, 2.1rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.est-nav__lista a {
  display: inline-block;
  padding-block: .35rem;
  font-size: var(--est-step--1);
  font-weight: 400;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
  color: inherit;
  opacity: .82;
  /* The hover underline draws in from the left (background-size below). */
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: opacity var(--est-dur) var(--est-ease),
              background-size var(--est-dur) var(--est-ease);
}
.est-nav__lista li:not(.selected) > a:hover,
.est-nav__lista li:not(.selected) > a:focus-visible { background-size: 100% 1px; }
.est-nav__lista a:hover,
.est-nav__lista .selected > a,
.est-nav__lista .ancestor > a { opacity: 1; }
.est-nav__lista .selected > a { box-shadow: inset 0 -1px 0 0 var(--est-acento); }

/* {% show_menu 0 1 0 1 %} emits the active branch's children as a nested <ul>.
   A second row inside a fixed bar would break its height; the sub-pages stay
   reachable from the page body and from the mobile panel below. */
@media (min-width: 62em) {
  .est-nav__lista ul { display: none; }
}

.est-langs {
  display: flex;
  align-items: center;
  gap: .1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.est-langs__enlace {
  display: inline-block;
  padding: .35rem .55rem;
  font-size: var(--est-step--2);
  font-weight: 500;
  letter-spacing: .14em;
  text-decoration: none;
  color: inherit;
  opacity: .6;
}
.est-langs__enlace:hover { opacity: 1; }
.est-langs__enlace[aria-current="true"] { opacity: 1; color: var(--est-acento); }
.est-langs__separador { opacity: .35; user-select: none; }

/* --- 8. WhatsApp ---------------------------------------------------------- */

.est-wa {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  text-decoration: none;
  color: inherit;
}
.est-wa__icono { width: 18px; height: 18px; flex: none; fill: currentColor; }

.est-wa--cabecera {
  padding: .5rem 1.1rem;
  border: 1px solid var(--est-rule);
  border-radius: var(--est-radius-pill);
  font-size: var(--est-step--2);
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  transition: background-color var(--est-dur) var(--est-ease),
              color var(--est-dur) var(--est-ease);
}
.est-wa--cabecera:hover {
  background: var(--est-btn-solido-bg);
  color: var(--est-btn-solido-fg);
  border-color: var(--est-btn-solido-bg);
}

@media (max-width: 47.99em) {
  .est-wa--cabecera .est-wa__texto { display: none; }
  .est-wa--cabecera { padding: .5rem .7rem; }
}

/* --- 9. Mobile navigation panel ------------------------------------------- */

@media (max-width: 61.99em) {
  .est-header__menu { display: inline-flex; }

  .est-nav {
    position: fixed;
    inset: var(--est-cabecera) 0 auto 0;
    max-height: calc(100svh - var(--est-cabecera));
    overflow-y: auto;
    padding: 1.5rem clamp(1.25rem, 5vw, 2.5rem) 2.5rem;
    background: var(--est-ink);
    border-top: 1px solid var(--est-rule);
    visibility: hidden;
    opacity: 0;
    transform: translateY(-.5rem);
    transition: opacity var(--est-dur) var(--est-ease),
                transform var(--est-dur) var(--est-ease),
                visibility var(--est-dur);
  }
  .cms-toolbar-expanded .est-nav { inset-block-start: calc(var(--est-cabecera) + 46px); }

  .est-header--menu-abierto .est-nav {
    visibility: visible;
    opacity: 1;
    transform: none;
  }

  .est-nav__lista { flex-direction: column; align-items: stretch; gap: 0; }
  .est-nav__lista li { border-bottom: 1px solid var(--est-rule); }
  .est-nav__lista a { padding-block: .95rem; font-size: var(--est-step-0); }
  .est-nav__lista ul { list-style: none; margin: 0; padding-inline-start: 1.25rem; }
  .est-nav__lista ul li:last-child { border-bottom: 0; }
}

/* --- 10. Main ------------------------------------------------------------- */

/* flex-grow so body's column flexbox pushes the footer to the bottom edge of
   a short page; flex-shrink 0 so a tall page is never squeezed. */
#est-main { display: block; flex: 1 0 auto; }
/* Anchor links must not land under the bar. */
html { scroll-padding-top: calc(var(--est-cabecera) + 1rem); }

/* --- 11. The hero pattern -------------------------------------------------
   The approved direction's centrepiece, and deliberately generic so anything
   carrying type over a photograph reuses it rather than reinventing it.

   HANDOFF TO TASK 13 — templates/brand/hero.html should render

     <section class="est-hero est-portada" data-est-hero>
       <div class="est-portada__media">{% picture ... clase="est-portada__img" %}</div>
       <div class="est-portada__texto"><div class="est-wrap--ancho"> ... </div></div>
     </section>

   and keep .est-hero for whatever that plugin adds on top. `data-est-hero` is
   what makes the header go transparent over the photograph and solid past it;
   nothing appended later may override .est-portada's `display: grid`, which is
   what stacks the image, the scrim and the headline in one cell. */

.est-portada {
  position: relative;
  display: grid;
  grid-template-rows: 1fr auto;
  min-height: 100svh;
  isolation: isolate;
}
.est-portada__media {
  position: relative;
  grid-area: 1 / 1 / -1 / -1;
  overflow: hidden;
}
/* Absolute rather than height:100%: {% picture %} always writes real width and
   height attributes on the <img>, and this is what makes the photograph fill
   the frame regardless of its own aspect ratio without reintroducing CLS —
   .est-portada reserves the box with min-height before the image loads. */
.est-portada__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
/* The scrim. Binding gradient — see --est-scrim in est-tokens.css — plus a
   local shadow under the text block, bottom-left where the type sits. The
   binding gradient is lightest at mid-height, exactly where the headline
   starts, so a bright floor or façade there left the lead and the outline
   button unreadable. */
.est-portada::after {
  content: "";
  /* Positioned, or it paints UNDER .est-portada__media (position: relative)
     and the photograph hides the scrim entirely. Same stacking level as the
     media, later in tree order → above it; the text (z-index 1) stays on top. */
  position: relative;
  grid-area: 1 / 1 / -1 / -1;
  background:
    radial-gradient(ellipse 85% 62% at 0% 100%,
      rgba(18, 18, 19, .62) 0%, rgba(18, 18, 19, .38) 45%, rgba(18, 18, 19, 0) 100%),
    var(--est-scrim);
  pointer-events: none;
}
.est-portada__texto {
  grid-area: 2 / 1;
  z-index: 1;
  align-self: end;
  padding-block: clamp(2.5rem, 7vh, 5.5rem);
  /* The headline starts near mid-height, where the scrim is thinnest; a soft
     halo keeps the eyebrow and the h1 off a bright façade. */
  text-shadow: 0 1px 16px rgba(18, 18, 19, .5);
}
/* 11px sand is the first thing to vanish on a pale wall: a tighter halo. */
.est-portada__texto .est-eyebrow { text-shadow: 0 0 8px rgba(18, 18, 19, .85); }
.est-portada__texto .est-btn { text-shadow: none; }
/* Lighter than the ordinary muted role: this sits on a photograph rather than
   on flat ink, and the scrim can only do so much for mid-grey text. */
.est-portada__texto .est-lead {
  color: color-mix(in srgb, var(--est-paper) 86%, var(--est-ink));
}

/* Short variant for listing pages, where the headline is the whole content. */
.est-portada--breve { min-height: min(62svh, 34rem); }

/* --- 12. Project grid -----------------------------------------------------
   Edge to edge, three columns on desktop, hairline gutters showing the ink
   ground through them, caption over a bottom gradient inside each cell. */

.est-project-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--est-rejilla-canal);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 40em)  { .est-project-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64em)  { .est-project-grid { grid-template-columns: repeat(3, 1fr); } }

.est-project-card { display: block; }

.est-project-card__link {
  --est-celda-pad: clamp(1.1rem, 2.5vw, 1.9rem);
  position: relative;
  display: grid;
  grid-template-rows: 1fr auto auto;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  text-decoration: none;
  isolation: isolate;
}
.est-project-card__img {
  grid-area: 1 / 1 / -1 / -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.1s var(--est-ease);
}
.est-project-card__link::after {
  content: "";
  grid-area: 1 / 1 / -1 / -1;
  background: var(--est-scrim-pie);
  pointer-events: none;
}
.est-project-card__link:hover .est-project-card__img,
.est-project-card__link:focus-visible .est-project-card__img { transform: scale(1.045); }

.est-project-card__title {
  grid-area: 2 / 1;
  z-index: 1;
  align-self: end;
  margin: 0;
  padding-inline: var(--est-celda-pad);
  font-size: var(--est-step-1);
  font-weight: 350;
  line-height: 1.15;
  letter-spacing: -.014em;
}
.est-project-card__meta {
  grid-area: 3 / 1;
  z-index: 1;
  margin: .35rem 0 0;
  padding: 0 var(--est-celda-pad) var(--est-celda-pad);
  font-size: var(--est-eyebrow-size);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--est-sand);
}
/* A card with no title row still needs the bottom breathing space. */
.est-project-card__title:last-child { padding-bottom: var(--est-celda-pad); }

.est-project-card--vacia { padding-block: var(--est-section); }
.est-project-card--vacia p { margin: 0; color: var(--est-muted); }

/* --- 13. Project detail --------------------------------------------------- */

/* .est-project__hero carries .est-portada as well; nothing here may override
   that class's `display: grid`, which is what stacks the photograph, the scrim
   and the headline in one cell. */
.est-project__hero .est-eyebrow { color: var(--est-sand); }

/* Technical sheet, on an ink band directly under the photograph. */
.est-ficha {
  display: grid;
  gap: 1.75rem var(--est-gap);
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  margin: 0;
}
.est-ficha dt {
  margin: 0 0 .45rem;
  font-size: var(--est-eyebrow-size);
  font-weight: 600;
  letter-spacing: var(--est-eyebrow-track);
  text-transform: uppercase;
  color: var(--est-acento);
}
.est-ficha dd {
  margin: 0;
  font-size: var(--est-step-1);
  font-weight: 300;
  line-height: 1.25;
}

.est-related { padding-block: var(--est-section); }
.est-related__lista { margin: 0; padding: 0; list-style: none; }
.est-related__lista li + li { border-top: 1px solid var(--est-rule); }
.est-related__lista a {
  display: block;
  padding-block: 1rem;
  font-size: var(--est-step-1);
  font-weight: 300;
  text-decoration: none;
}
.est-related__lista a:hover { color: var(--est-acento); }

/* --- 14. Gallery ----------------------------------------------------------
   Edge to edge on ink, matching the project grid's hairline gutters. Plans and
   renders are line drawings: they get contained on mist rather than cropped. */

.est-gallery {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--est-rejilla-canal);
  margin: 0;
  padding: 0;
}
@media (min-width: 48em) { .est-gallery { grid-template-columns: repeat(2, 1fr); } }

.est-gallery__item { margin: 0; }
.est-gallery__item img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
/* Every third photograph runs the full width: the rhythm the direction asks
   for, without any editorial decision needed per project. */
@media (min-width: 48em) {
  .est-gallery__item:nth-child(3n + 1) { grid-column: 1 / -1; }
  .est-gallery__item:nth-child(3n + 1) img { aspect-ratio: 21 / 9; }
}
.est-gallery__item--plano img {
  object-fit: contain;
  background: var(--est-mist);
  aspect-ratio: 3 / 2;
}

/* --- 15. Services --------------------------------------------------------- */

.est-service-grid {
  display: grid;
  gap: var(--est-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.est-service-card {
  display: flex;
  flex-direction: column;
  gap: .6rem;
  padding-block: 1.75rem;
  border-top: 1px solid var(--est-rule);
}
.est-service-card__title {
  margin: 0;
  font-size: var(--est-step-1);
  font-weight: 350;
  letter-spacing: -.014em;
}
.est-service-card__title a { text-decoration: none; }
.est-service-card__title a:hover { color: var(--est-acento); }
.est-service-card__text { margin: 0; color: var(--est-muted); }

.est-media {
  display: block;
  width: 100%;
  margin-block: 2.5rem;
  border-end-start-radius: var(--est-radius-arc);
}

/* --- 16. CTA band ---------------------------------------------------------
   The single saturated moment per page, and the only place teal-deep is
   allowed. Task 13's EstCTABandPlugin should render `.est-cta est-cta-band`. */

.est-cta {
  --est-fg:     var(--est-paper);
  --est-bg:     var(--est-teal-deep);
  --est-muted:  color-mix(in srgb, var(--est-paper) 78%, var(--est-teal-deep));
  --est-rule:   color-mix(in srgb, var(--est-paper) 30%, var(--est-teal-deep));
  --est-acento: var(--est-sand);
  --est-btn-solido-bg: var(--est-paper);
  --est-btn-solido-fg: var(--est-teal-deep);
  padding-block: var(--est-section);
  color: var(--est-fg);
  background-color: var(--est-bg);
}

/* --- 17. Footer ----------------------------------------------------------- */

.est-footer { padding-block: var(--est-section) 2.5rem; }
.est-footer a { color: inherit; }

.est-footer__grid {
  display: grid;
  gap: var(--est-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
}
.est-footer__col p { margin: 0 0 .5rem; }
.est-footer__col .est-eyebrow { margin-bottom: 1.1rem; }

/* Replaces the inline style="list-style:none;padding:0;margin:0" the brief
   put on the social list: structure in the template, presentation here. */
.est-lista-limpia { margin: 0; padding: 0; list-style: none; }
.est-lista-limpia li + li { margin-top: .4rem; }

.est-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.5rem;
  margin-top: var(--est-section);
  padding-top: 1.5rem;
  border-top: 1px solid var(--est-rule);
  font-size: var(--est-step--1);
  color: var(--est-muted);
}
.est-footer__legal p { margin: 0; }

/* --- 18. Contact form -----------------------------------------------------
   .est-form__trampa is declared at the top of this file (Task 11) and must
   not be repeated here. */

.est-form { max-width: 38rem; }
.est-form__campo { display: grid; gap: .45rem; margin-block: 0 1.5rem; }
.est-form__campo label {
  font-size: var(--est-eyebrow-size);
  font-weight: 600;
  letter-spacing: var(--est-eyebrow-track);
  text-transform: uppercase;
  color: var(--est-acento);
}
.est-form__campo :is(input, textarea, select) {
  padding: .85rem 1rem;
  border: 1px solid var(--est-rule);
  border-radius: var(--est-radius-sm);
  background: var(--est-bg);
  color: var(--est-fg);
}
.est-form__campo :is(input, textarea, select):focus-visible { border-color: var(--est-acento); }
.est-form__campo textarea { min-height: 9rem; resize: vertical; }
.est-form__error { color: var(--est-oxblood); font-size: var(--est-step--1); }

.est-mensajes { margin: 0 0 2rem; padding: 0; list-style: none; }
.est-mensajes__item {
  padding: .9rem 1.15rem;
  border-inline-start: 3px solid var(--est-acento);
  background: var(--est-mist);
}
.est-mensajes__item--error { border-inline-start-color: var(--est-oxblood); }

/* --- 19. Motion and print ------------------------------------------------- */

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

@media print {
  .est-header, .est-footer, .est-skip, .est-wa { display: none !important; }
  #est-main { padding-top: 0; }
  .est-portada { min-height: 0; }
  .est-portada::after { display: none; }
}

/* ===========================================================================
   Task 13 — es.taller structural plugins (brand app). Appended per the
   handoff at the top of this file: .est-hero, .est-sec__num, .est-arcos,
   .est-cta-band and .est-manifesto are defined here, exactly once.
   =========================================================================== */

/* --- 20. Section wrapper --------------------------------------------------- */

.est-sec__num { color: var(--est-acento); margin-inline-end: .75rem; }
.est-sec__body { margin-top: clamp(1.5rem, 4vw, 3rem); }
.est-sec__body:empty { display: none; }

/* --- 21. Hero plugin --------------------------------------------------------
   .est-hero itself carries no box rules: .est-portada (§11) already owns the
   grid, the min-height and the scrim. This class only styles what the plugin
   adds on top of that pattern — the CTA row. */

.est-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
}

/* --- 22. Arc divider ---------------------------------------------------------
   The brand's arc motif (echoing the four arched modules of the wordmark),
   used as a quiet transition between bands. Colour comes from currentColor,
   set per `.est-arcos--<variante>`; the geometry itself lives inline in
   templates/brand/arc_divider.html — there is no static/src/img/est-arcos.svg. */

.est-arcos {
  display: block;
  width: 100%;
  max-width: var(--est-wrap);
  margin-inline: auto;
  padding-block: clamp(1.5rem, 4vw, 3rem);
  color: var(--est-acento);
}
.est-arcos--sand    { color: var(--est-sand); }
.est-arcos--oxblood { color: var(--est-oxblood); }
.est-arcos svg {
  display: block;
  width: 100%;
  height: clamp(48px, 8vw, 96px);
}

/* --- 23. CTA band -------------------------------------------------------------
   `.est-cta` (§16) supplies the teal-deep colour tokens; this is the
   plugin's own layout. */

.est-cta-band { text-align: center; }
.est-cta-band .est-h2,
.est-cta-band .est-lead { margin-inline: auto; }
.est-cta-band .est-lead { margin-block-end: 2rem; }

/* --- 24. Manifesto ------------------------------------------------------------
   A two-column pairing on wide viewports: a large pull-quote beside the
   body copy, stacking on narrow ones. */

.est-manifesto {
  display: grid;
  gap: var(--est-gap);
  padding-block: var(--est-section);
}
@media (min-width: 900px) {
  .est-manifesto { grid-template-columns: 1fr 1.4fr; }
}
.est-manifesto__cita {
  margin: 0;
  font-size: var(--est-step-2);
  font-weight: 250;
  line-height: 1.15;
  letter-spacing: -.018em;
  color: var(--est-teal);
}

/* ===========================================================================
   Task 14 — es.taller data-driven plugins (services, process, projects,
   contact) plus the homepage finish. Appended per the Task 13 handoff: never
   re-declare a rule above, only add to or (via later cascade order, as with
   .est-manifesto below) deliberately override one.
   =========================================================================== */

/* --- 25. Manifesto ink band -------------------------------------------------
   Turns §24's single-element wrap+grid into a full-bleed ink interstitial
   band (templates/brand/manifesto.html): the outer .est-manifesto now
   supplies only the ink background and vertical padding, edge to edge; the
   grid and the max-width move to .est-manifesto__inner, the block's one and
   only .est-wrap. Sand, not teal, for the pull-quote — teal-on-ink reads too
   close in value; sand is the palette's designated accent on dark. */

.est-manifesto {
  display: block;
  padding-block: var(--est-section);
  --est-fg:     var(--est-paper);
  --est-bg:     var(--est-ink);
  --est-muted:  color-mix(in srgb, var(--est-paper) 66%, var(--est-ink));
  --est-rule:   color-mix(in srgb, var(--est-paper) 18%, var(--est-ink));
  --est-acento: var(--est-sand);
  color: var(--est-fg);
  background-color: var(--est-bg);
}
.est-manifesto__inner {
  display: grid;
  gap: var(--est-gap);
}
@media (min-width: 900px) {
  .est-manifesto__inner { grid-template-columns: 1fr 1.4fr; }
}
.est-manifesto__cita { color: var(--est-sand); }

/* --- 26. Service grid -------------------------------------------------------
   Always a child of EstSectionPlugin (§20 supplies the eyebrow/title and the
   one .est-wrap), so this template never wraps itself. */

.est-service-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--est-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.est-service-card { padding-top: 1.5rem; border-top: 1px solid var(--est-rule); }
.est-service-card__title { font-size: var(--est-step-1); font-weight: 400; margin: 0 0 0.5rem; }
.est-service-card__title a {
  text-decoration: none; color: inherit;
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: background-size var(--est-dur) var(--est-ease), color var(--est-dur) var(--est-ease);
}
.est-service-card__title a:hover,
.est-service-card__title a:focus-visible { background-size: 100% 1px; color: var(--est-acento); }
.est-service-card__text { color: var(--est-muted); margin: 0; }

/* --- 27. Process timeline --------------------------------------------------- */

.est-timeline-seccion { padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem) var(--est-section); }
.est-timeline { list-style: none; margin-block: 0; padding: 0; }
.est-timeline__item { position: relative; display: grid; grid-template-columns: 3rem 1fr;
  column-gap: 1.25rem; padding-bottom: 2.75rem; }
/* The path: runs from under this stage's node to the next one's. */
.est-timeline__item::before { content: ""; position: absolute; left: calc(1.5rem - .5px);
  top: 3rem; bottom: 0; width: 1px; background: var(--est-rule); }
.est-timeline__item:last-child { padding-bottom: 0; }
.est-timeline__item:last-child::before { display: none; }
.est-timeline__num { grid-row: span 2; width: 3rem; height: 3rem; border-radius: 50%;
  border: 1px solid var(--est-acento); color: var(--est-acento); background: var(--est-bg);
  display: grid; place-items: center; font-size: var(--est-step--1); letter-spacing: .08em;
  transition: background-color .6s var(--est-ease), color .6s var(--est-ease); }
/* js/est-motion.js: set once the stage passes mid-viewport, and kept. */
.est-timeline__item--hecha .est-timeline__num { background: var(--est-acento); color: var(--est-bg); }
.est-timeline__title { font-size: var(--est-step-1); font-weight: 400; line-height: 1.25;
  margin: 0 0 .6rem; padding-top: .6rem; }
.est-timeline__text { color: var(--est-muted); margin: 0; max-width: 60ch; }
@media (min-width: 900px) {
  .est-timeline { max-width: 1040px; }
  .est-timeline__item { grid-template-columns: 4rem minmax(0, 1fr) minmax(0, 1.7fr);
    column-gap: clamp(1.5rem, 3vw, 3rem); padding-bottom: 3.5rem; }
  .est-timeline__item::before { left: calc(2rem - .5px); top: 4rem; }
  .est-timeline__num { grid-row: auto; width: 4rem; height: 4rem; font-size: var(--est-step-0); }
  .est-timeline__title { padding-top: 1.1rem; margin: 0; }
  .est-timeline__text { padding-top: 1.1rem; }
}

/* --- 28. Contact form plugin ------------------------------------------------
   .est-form itself is styled at §18; this only sizes the wrapping section. */

.est-contact { padding-block: var(--est-section); max-width: 46rem; }

/* --- 29. Retrato ------------------------------------------------------------
   Portrait beside text (templates/brand/retrato.html). The photo's top is a
   full arch — the wordmark's arched modules at portrait scale — so the
   studio photos read as part of the brand rather than as stock headshots. */

.est-retrato { padding-block: var(--est-section); }
.est-retrato + .est-retrato { padding-top: 0; }
.est-retrato__inner {
  display: grid;
  gap: var(--est-gap);
  align-items: center;
}
@media (min-width: 900px) {
  .est-retrato__inner { grid-template-columns: 5fr 7fr; column-gap: clamp(2.5rem, 6vw, 6rem); }
  .est-retrato--invertido .est-retrato__inner { grid-template-columns: 7fr 5fr; }
  .est-retrato--invertido .est-retrato__figura { order: 2; }
}
.est-retrato__figura { margin: 0; max-width: 32rem; }
.est-retrato__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 999px 999px 0 0 / 40% 40% 0 0;
  background: var(--est-mist);
}
.est-retrato__pie {
  margin-top: .9rem;
  font-size: var(--est-eyebrow-size);
  letter-spacing: var(--est-eyebrow-track);
  text-transform: uppercase;
  color: var(--est-muted);
}
.est-retrato__texto .est-prose p:first-child { font-size: var(--est-step-1); line-height: 1.45; }
.est-retrato__cta { margin: 2rem 0 0; }

/* --- 30. Motion: first-load loader, page transitions, scroll reveals -------
   All three are enhancements that fail open: no JS, no support or reduced
   motion means no loader, a plain navigation and every element visible. */

/* The loader. Only js/est-loader.js (blocking, in <head>) sets .est-cargando,
   once per session. The exit is part of the same CSS animation, so the
   overlay leaves on its own; it never takes clicks while it is up. */
.est-loader { display: none; }
.est-cargando .est-loader {
  display: grid;
  place-items: center;
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--est-ink);
  color: var(--est-paper);
  pointer-events: none;
  animation: est-loader-salida .55s var(--est-ease) .7s forwards;
}
.est-loader__marca { width: clamp(3.5rem, 8vw, 5rem); height: auto; overflow: visible; }
.est-loader__marca path {
  transform-box: fill-box;
  transform-origin: center;
  opacity: 0;
  animation: est-loader-modulo .4s var(--est-ease) forwards;
}
.est-loader__marca path:nth-child(2) { animation-delay: .08s; }
.est-loader__marca path:nth-child(3) { animation-delay: .16s; }
.est-loader__marca path:nth-child(4) { animation-delay: .24s; }
@keyframes est-loader-modulo {
  from { opacity: 0; transform: scale(.55); }
  to   { opacity: 1; transform: none; }
}
@keyframes est-loader-salida {
  to { clip-path: inset(0 0 100% 0); visibility: hidden; }
}

/* Page transitions: native cross-document view transitions. The header is
   its own group, so it holds still while the page under it changes. */
@view-transition { navigation: auto; }
.est-header { view-transition-name: est-cabecera; }
::view-transition-old(root) { animation: est-vt-salida .2s var(--est-ease) both; }
::view-transition-new(root) { animation: est-vt-entrada .38s var(--est-ease) both; }
@keyframes est-vt-salida { to { opacity: 0; } }
@keyframes est-vt-entrada { from { opacity: 0; transform: translateY(.75rem); } }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* Scroll reveals. js/est-motion.js adds .est-revelar only to elements still
   below the fold, .est-revelado as they enter, and removes both when the
   transition ends so the element's own transitions come back. */
.est-revelar {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity .9s var(--est-ease) var(--est-retraso, 0ms),
              transform .9s var(--est-ease) var(--est-retraso, 0ms);
}
.est-revelar.est-revelado { opacity: 1; transform: none; }
